observeChanges:changed callback called with unexpected "field" value


#1

In my project I have a Meteor.method that changes the value of a two embedded fields.

When the observeChanges “changed” callback fires on the client, the “field” argument contains the root parent field that changed, and all of its descendants whereas I was expecting the result to be less verbose. Is this the expected functionality?

i.e. I have a document of the form {a:{…},b:{…}} If I change “b.c.d.e” to 1, the “field” argument passed to observeChanges:changed is set to the field “b” containing all of its children.


#2

I’ve investigated it further, here is the entry from my oplog:

{ “ts” : Timestamp(1431940343, 1), “h” : NumberLong("-408383836406542824"), “v” : 2, “op” : “u”, “ns” : “meteor.fields_meta”, “o2” : { “_id” : “QjjZXDAgenKni7jF5” }, “o” : { “$set” : { “fields.lastName.busy_time” : 1431940343914, “fields.lastName.busy_owner” : null } } }

Yet, the “field” value that arrives to the client in a message is the entire “fields” object.


#3

This is the expected behaviour. I have been trying to find a reference to it (which I know I have seen), but have failed :worried: so far. I’ll update this post if and when I do.


#4

that’s unfortunate, I think this decreases the utility of such a function.


#5

Still not managed to find the reference, but inspection of the code itself is clear enough:

// General helper for diff-ing two objects.
// callbacks is an object like so:
// { leftOnly: function (key, leftValue) {...},
//   rightOnly: function (key, rightValue) {...},
//   both: function (key, leftValue, rightValue) {...},
// }
LocalCollection._diffObjects = function (left, right, callbacks) {
  _.each(left, function (leftValue, key) {
    if (_.has(right, key))
      callbacks.both && callbacks.both(key, leftValue, right[key]);
    else
      callbacks.leftOnly && callbacks.leftOnly(key, leftValue);
  });
  if (callbacks.rightOnly) {
    _.each(right, function(rightValue, key) {
      if (!_.has(left, key))
        callbacks.rightOnly(key, rightValue);
    });
  }
};

The underscore each method is used to iterate over a list (i.e. a single level of object depth).


#6

I guess I must be confused about how Meteor tails and utilizes the oplog. I’d have expected it to replay the modifications to the client with minimongo acting as a pseudo replication set member.

Right now the extra fields and values are sent as part of the message before being processed by minimongo on the client side.


#7

That _diffObjects() method is also used by ddp-server/package.js and ddp-server/livedata_server.js - so (despite its location in minimongo) is used as part of the server-side oplog diffing as well.


#8

thanks for pointing that out. I’ll have to think about things a bit more now that I know this constraint exists.