6

I am writing a piece of software that connects to a Meteor server via DDP to read data.

The problem I am facing is figuring out how to differentiate between a NEW document getting added to a collection and getting notified about already-existing documents.

When I first connect to the server, I get a series of added messages to populate the clientside collection. I don't know how to differentiate between those messages, and the ones that come later, indicating a new document was added live. This gets even worse when the DDP client needs to reconnect to the server, at which point all of the current documents are again sent as added messages.

Allie the Icon
  • 2,142
  • 2
  • 18
  • 26
  • This is a recurring question. does this solution work for you? http://stackoverflow.com/questions/10218534/cursor-observeadded-behavior-in-meteor – Christian Fritz Jul 30 '14 at 20:25
  • It's a tad different because that question (and the one it links to) are both talking about writing direct Meteor code rather than using DDP in a client app. But it might be close enough to close as dupe. The bottom line is that it appears what I need to do is handle figuring out the distinction myself in my own code (probably by including a timestamp in new documents). I was hoping for a built-in utility to do it. – Allie the Icon Jul 30 '14 at 21:33
  • My gut instinct is to say you should ignore everything that's `added` before the `ready` message arrives for that subscription id. I'm pretty sure that this is what fires the `Meteor.subscribe` callback referred to in the linked^2 example. HOWEVER, I am not convinced that this `ready` message is actually guaranteed to arrive after all the initial `added` messages, which means that this technique might not be reliable. Please let me know if you'd like an example and I will happily post. I'd also love to know what MDG suggest! – richsilv Jul 30 '14 at 23:01

2 Answers2

10

Took me a while to actually realise, but this is exactly the kind of thing that the low-level publish API is designed for. Read the section from "Alternatively, a publish function can..." downwards, and it should be pretty clear how you only send added messages for genuinely new documents. Or to provide a simple example:

Both server and client:

MyData = new Meteor.Collection("mydata");

Client:

Meteor.subscribe('myPub', myFilter);

Server:

Meteor.publish('myPub', function(filter) {
  var self = this;
  var initializing = true;

  var handle = MyData.find(filter).observeChanges({
    added: function (id, fields) {
      if (!initializing)
        self.added("mydata", id, fields);
    },
    changed: function(id, fields) {
      self.changed("mydata", id, fields);
    },
    removed: function (id) {
      self.removed("mydata", id);
    }
  });
  initializing = false;
  self.ready();

  self.onStop(function () {
    handle.stop();  // v. important to stop the observer when the subscription is stopped to avoid it running forever!
  });
});

UPDATE

This is so fundamental I've actually written a blog post about it.

richsilv
  • 7,993
  • 1
  • 23
  • 29
  • Ah ha! This does seem to be exactly the type of solution I was looking for! I haven't had a chance to try it out yet but I am accepting it as it does clearly seem to be the intended method of accomplishing this. – Allie the Icon Aug 01 '14 at 23:51
3

I have had this problem in the past and found a solution. Set a variable at first render and change the variable after the intial observe - example:

var initializing = true;

var handle = Collection.find().observe({
  added: function (item) {
    if (!initializing)
        // do stuff with newly added items, this check skips the first run
  }
});

initializing = false;
  • Actually, the function is called "observeChanges", and it works like this https://docs.meteor.com/api/collections.html#Mongo-Cursor-observeChanges – Marc Oct 26 '16 at 09:32