Why does meteor undo changes to collections nested in an observer method?

孤街浪徒 提交于 2019-12-21 19:58:05

问题


I am trying to implement something like this:

/* We use the command pattern to encode actions in
   a 'command' object. This allows us to keep an audit trail
   and is required to support 'undo' in the client app. */
CommandQueue.insert(command);

/* Queuing a command should trigger its execution. We use
   an observer for this. */
CommandQueue
   .find({...})
   .observe({
       added: function(command) {
           /* While executing the action encoded by 'command'
              we usually want to insert objects into other collections. */
           OtherCollection.insert(...)
       }
   });

Unfortunately it seems that meteor keeps the prior state of the OtherCollection while executing the transaction on CommandQueue. Changes are made temporarily to the OtherCollection. As soon as the transaction on CommandQueue finishes, the prior state of the OtherCollection will be restored, though, and our changes disappear.

Any ideas why this is happening? Is this intended behaviour or a bug?


回答1:


This is the expected behavior, though it is a little subtle, and not guaranteed (just an implementation detail).

The callback to observe fires immediately when the command is inserted into CommandQueue. So the insert to OtherCollection happens while the CommandQueue.insert method is running, as part of the same call stack. This means the OtherCollection insert is considered part of the local 'simulation' of the CommandQueue insert, and is not sent to the server. The server runs the CommandQueue insert and sends the result back, at which point the client discards the results of the simulation and applies the results sent from the server, making the OtherCollection change disappear.

A better way to do this would be to write a custom method. Something like:

Meteor.methods({
  auditedCommand: function (command) {
    CommandQueue.insert(command);

    var whatever = someProcessing(command)
    OtherCollection.insert(whatever);
  }
});

Then:

Meteor.call('auditedCommand', command);

This will show up immediately on the client (latency compensation) and is more secure as clients can't insert to CommandQueue without also adding to OtherCollection.

EDIT: this will probably change. The added callback shouldn't really be considered part of the local simulation of CommandQueue.insert. Thats just the way it works now. That said, a custom method is probably still a better approach for this, it will work even if other people add commands to the command queue, and is more secure.




回答2:


I'm not sure about your observe behavior but we accomplished the same thing using a server-side allow method:

CommandQueue.allow ({
  insert: function (userId, doc) {
    OtherCollection.insert(...);
    return (userId && doc.owner === userId);
  }
});

This is also more secure than putting this logic client side.



来源:https://stackoverflow.com/questions/14250259/why-does-meteor-undo-changes-to-collections-nested-in-an-observer-method

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!