meteor-collection-hooks icon indicating copy to clipboard operation
meteor-collection-hooks copied to clipboard

Simulate resulting doc on before.update hooks

Open gwendall opened this issue 10 years ago • 15 comments

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)

gwendall avatar Feb 11 '15 16:02 gwendall

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

mizzao avatar Feb 11 '15 17:02 mizzao

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?

bensmeets avatar Mar 23 '15 13:03 bensmeets

@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;
}

gwendall avatar Mar 23 '15 13:03 gwendall

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.

matb33 avatar Mar 23 '15 13:03 matb33

@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 avatar Mar 23 '15 14:03 bensmeets

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.

bensmeets avatar Mar 23 '15 14:03 bensmeets

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.

matb33 avatar Mar 23 '15 14:03 matb33

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 :)

bensmeets avatar Mar 25 '15 10:03 bensmeets

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.

matb33 avatar Apr 22 '15 18:04 matb33

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.

trusktr avatar Mar 07 '16 16:03 trusktr

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

pdiniz13 avatar May 18 '16 01:05 pdiniz13

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.

chneau avatar May 20 '16 14:05 chneau

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

zimme avatar Feb 12 '17 10:02 zimme

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.

davidsavoie1 avatar Aug 17 '18 13:08 davidsavoie1

This is still needed, any news? :)

luixal avatar Nov 22 '18 10:11 luixal