• Meteor

Publishing a Cursor

From the class:  Publish Subscribe in Meteor

So far in our study of Publish functions, we've been calling the functions that send EDP messages ourselves. In this example, I've called the Added function twice, which sends the Added message to the client. And then, I send the Ready message by calling the Ready function. And that tells the client that all of the initial data is ready.

But typically in our applications, we don't call these functions directly. Instead, we return a cursor.

In this example, returning the result of calling items.find-- so by calling the Find method on a collection that we have called Items-- this creates something called a cursor. And when we return that cursor, somehow Meteor is able to do the right thing and send the right messages to the client.

In the rest of the video, I'll show you how.

I've taken you over to the Meteor source code and opened up Live Data Server. If you look inside one of the subscription methods called Run Handler, if you recall this, is the function that gets called when our Publish function first runs. What we can do is scroll down to where we get a result. And you can see that the result gets stored in this Result variable.

And then, if we scroll down just a little bit further, Meteor checks whether or not the result is a cursor. And the way that it's able to do that is by calling this function here-- Is Cursor-- with the response. And it's a pretty simple mechanism to decide whether or not it's a cursor. It's a cursor if it has a function on it called _Publish Cursor.

Now, of course, this API could change at some point. But for now, if there's a function there called Publish Cursor, Meteor will go ahead and call it with this subscription object passed in as a parameter.

Then, once that function has run, it will send the Ready message on our behalf.

So we can simulate this by creating an object that has a function like this to see how it works. Let's start up Meteor application and go back to our application code.

For now, instead of returning a cursor by calling the Find function on our collection, let's return a custom object. And I'll define that object up here. And all we need to do is to put a function called Publish Cursor, which will take the subscription as a parameter. And then, I'll just print out for now a console log that says we're inside the Publish Cursor function. And just by returning this object here, this function will get called.

And now, what I'll do is I'll go down to the bottom. And we'll use the DDP tools to connect and subscribe to the Items subscription. On the right, you can see the inside Publish Cursor function printed to the console. And so we've successfully called our Publish Cursor function. And on the lower left, you can see the Ready message gets sent for us automatically.

Now, what this function would do more realistically is send some Added messages, one for each document in the collection. So to simulate, we might say that we'll call the Added method for the Items collection for Item 1, and then do the same thing for Item 2. And then, I'll go down into the bottom console again, and we'll subscribe to the Items publication.

It looks like I just used the wrong object. And instead of using this, what I do is call Added on the subscription. Let's try that one more time. This time it worked OK.

So what we're doing is calling the Added function of our subscription twice. And that sends these two messages to the client. And then, Meteor automatically sends the Ready message once we're done here.

So how does all of this relate to cursors themselves? Well, what the cursor needs to be able to do is to send the initial document set for the query results. And then, it needs to be able to send changed messages or moved messages, or even added messages for additional documents that might get added later.

Now, this isn't a class on Mini Mongo or on Mongo collections, but I will talk about one function of collections here, so that we see what's happening. I'm going to not use a cursor directly. I'm going to continue to use our custom publisher. But what I will do is call items.find. So this will create our cursor object. And then, I can call the Observed Changes method on that.

And what will happen is Mini Mongo and Mongo Live data will call this function, to call the Callback functions in here, for each type of event that happens. And so every time a document is added, the Added function gets called. And every time a document is changed, the Change function is called, and so on.

And what Meteor does for us with cursors is plug these Callback functions into the subscription. And so for here, we can call the subscription Added. And again, for the Change method. And when I save that, we'll come back down to the bottom and try it out.

And what you're seeing here is simply by calling the Observed Changes function of the cursor, this Added function will get called every time a new result is added to the set. And then, we'll call the Added method of our subscription, sending down each one of these Added messages to the client who is subscribed to this data set. And then, finally, when that's done, again, Meteor automatically sends this Ready message saying we have the entire result set.

And then, down the line, if the document changes or is removed from the set, these callbacks will get called. And they'll call the Subscription Changed and Removed messages.

One last thing we typically would need to do, if we're using our own Publish Cursor function. The Observe Changes function returns a handle. And what we need to do is, when the subscription is stopped, we can register a callback that will get called. And in that callback, we want to make sure to stop our observer. And so that it doesn't continue to run even after the client has unsubscribed.

Great. It looks like everything is still working properly.

Before we conclude, I've taken us over to the Mongo Live Data package and opened up the collection.js so we can look at the actual implementation of Publish Cursor for a cursor. And what you can see here is the implementation looks very similar to what we just created.

So on the cursor itself, Meteor calls Observe Changes, and plugs in these callbacks, just like we did. And down below, when the subscription stops, Meteor stops the Observe handle.

So hopefully, this video gave you a better idea of some of the magic that is happening when we return a cursor from a Publish function.