Meteor-Community-Packages / meteor-collection-hooks

Meteor Collection Hooks
https://atmospherejs.com/matb33/collection-hooks
MIT License
657 stars 92 forks source link

Simulate resulting doc on before.update hooks #91

Open gwendall opened 9 years ago

gwendall commented 9 years ago

It would be handy to be able to simulate (using the initial doc + the modifier) what the doc after update would look like. It would make things like security checks pretty easy - right now we have to check $set, $addToSet, etc attributes manually to control what fields are about to get updated. Is there anything on the roadmap for that? If not that would not be too hard, just patching what was done on minimongo. (https://github.com/meteor/meteor/blob/07b6a2245a1e091830844881e7376c38adda3592/packages/minimongo/modify.js)

mizzao commented 9 years ago

Might help consolidate the logic for this if hooks were integrated into core (#92 and meteor/meteor#395).

bensmeets commented 9 years ago

I'm running into this one right now, I (try to) use the before.update hook to calculate some computed fields on the doc. But since there are quite some dependencies on the calculation on different fields in either the doc or the modifier (depending on which one is set and which one will be overridden by the modifier) it's a bit of a headache.

Did someone manage to find a smarter solution than what I'm currently thinking of which is a whole bunch of "if this then that or else use modifier if set" kind of code?

gwendall commented 9 years ago

@bensmeets Thinking about it now, you could do that through a dummy collection, ie:

TempCollection = new Mongo.Collection("temp");
var simulateDoc = function(doc, modifier) {
  TempCollection.insert(doc);
  var selector = { _id: doc._id };
  TempCollection.update(selector, modifier);
  var simulation = TempCollection.findOne(selector);
  TempCollection.remove(selector);
  return simulation;
}
matb33 commented 9 years ago

I agree it would be helpful. Have any of you tried just leveraging LocalCollection._modify directly? Something like:

coll.before.update(function (userId, doc, fieldNames, modifier, options) {
  LocalCollection._modify(doc, modifier);
  // doc should be simulated (I think)... do some logic
});

It would be good to try this in the wild for a bit to get a feel for it.

bensmeets commented 9 years ago

@gwendall Quite the creative solution :+1:

@matb33 Tried but I can't seem to find how to call _modify. Both through LocalCollection._modify as through MyCollectionName._modify I get an method undefined error. Do you happen to know how to call it?

bensmeets commented 9 years ago

I've got "some" sort of access to "_modify" in the client through

Package.minimongo.LocalCollection._modify

Callable, but it returns undefined in the server. Checked, the function does exist on the server, but for now still returns undefined.

matb33 commented 9 years ago

What you need to do is find a way to use minimongo on the server. I'll be honest... I don't remember how to do this without packages. My meteor projects are all made up entirely of packages, no client or server etc folders... so for me it's easy, I just api.use("minimongo", ["server", "client"]); from whichever of my app packages would need access to LocalCollection.

Whatever the equivalent would be for non-all-package projects, that's what you're looking for.

bensmeets commented 9 years ago

I couldn't get it exactly right, but I'm using a variation of @gwendall 's code. Like this:

simulateDocumentModifier: function (doc, modifier) {
    var c = new Package.minimongo.LocalCollection('simulations');
    c.insert(doc);

    var sel = {
      _id: doc._id
    };

    c.update(sel, modifier);

    var sim = c.findOne(sel);
    c.remove(sel);

    return sim;
  }

But the effect is a bit opaque. Just hoping I'm not creating a lot of overhead or database collections with it. It works though :)

matb33 commented 9 years ago

If using LocalCollection._modify(doc, modifier); as I mentioned actually does work, perhaps I could have the collection-hooks package use the minimongo package on both server and client, and offer a CollectionHooks.modify or something like that which just wraps LocalCollection._modify(doc, modifier);

I'm hoping someone can confirm that using LocalCollection._modify(doc, modifier); does what we would need it to do.

trusktr commented 8 years ago

Yep, depending on minimongo (serverside included) and using LocalCollection._modify works great. It's not publicly documented Meteor API, so took a while for me to find it. You might not even need to wrap it. In the before.update and before.upsert hooks, maybe you can just have oldDoc and newDoc parameters? But, documenting the use of modify function would also work.

pdiniz13 commented 8 years ago

Worked for me as well, as long as the minimongo dependency is there for both client and server, this solution works very well.

chneau commented 8 years ago

Hello, LocalCollection._modify works super fine for me !

I think it could be a good thing if " LocalCollection._modify " was on the README as a tip to get the result doc in updates.

zimme commented 7 years ago

I'll look into wrapping LocalCollection._modify and attaching it to this inside the hooks.

davidsavoie1 commented 6 years ago

Hi there!

Has there been any development or "official" support for this now? It would indeed be way easier to fire the proper hooks if we could diff between current and to-be-updated document. I'm just starting to integrate collection hooks in my app, and this is the most difficult thing for me so far.

Is the proposed LocalCollection._modify still relevant and working (since this thread dates a little...)?

Thanks all for the nice library though.

luixal commented 5 years ago

This is still needed, any news? :)