Mastering Parse Live Queries
Because I’ve seen some developers in the Back4App and Parse communities sometimes struggling to understand how Parse Live Query works, I wrote this article to explain all different events that Parse Live Query can fire and how to maintain a collection of Parse objects real-time updated on the client-side. So let’s get started! First of all, I created a Parse App at Back4App and a very simple class to illustrate the many different events that Parse Live Query can fire. The name of my class is Todo and I added two columns:
- a
title
column; - an
isClosed
column, which stores if the todo object is either closed or not.
Then I populated my database with some objects:
- Create Account, which I marked as closed;
- Learn Live Query, which I marked as not closed.
The picture below shows my database at the end:
Nice! Now we have some data to play with. In order to use Live Query with this Todo class also needed to enable it in the Server Settings Menu. I had to create a custom subdomain to which I will later connect my SDK, activate Live Query, and select the class in which I wanted to listen for the events. There is a detailed guide on how to enable Parse Live Query. The picture below shows my settings at the end:
Now let’s dive into the code. I created a simple node.js project that will listen for the Live Query events. In a similar way, you can connect pretty much any platform to Live Query. I installed the Parse SDK and required it in my program. Since it is a node.js project, I had to require `parse/node`.
After that, I set my server URL (which was the one that I’ve created before using the dashboard) and initialized the SDK using my app id and my javascript key, which I can find also in the dashboard under App Settings. Finally, I created and called an async main function that executes our program.
$ npm install parse
Our setup is ready, and I could actually start coding. The way Parse Live Query works is through Parse Queries. I just had to create a regular query like this one, which is filtering out the todo objects not closed yet:
In the next step, I subscribed to this query and used this subscription to listen to the different events that Parse Live Query can fire: open, create, update, enter, leave, delete, and close.
The open event fires when the server confirms that the subscription is opened.
The create event fires every time a new object is created and matches the query. The new object is sent as a parameter of the callback function.
In a similar way, the update event fires when you have an object which was already a match for the query, and this object gets updated. Note that this event will only fire if this object fulfills the query both before and after being updated.
The enter event fires when you have an object that was not a match for the query, and, after updated, it fulfills the query.
The leave event is the opposite. It fires when you have an object that was part of the query, and, after updated, does not fulfill the query anymore.
The delete event gets triggered when an object that is part of the query gets deleted.
And last, but not least, the close event gets fired if, for any reason, your program loses connection with the Parse Live Query server.
Ok. At this moment I had all events in place, and I wanted to give some functionality to them. A common use case for the live query is maintaining a list of objects live updated. So I made this program maintain the list of not closed todo objects always updated. I added a variable to store the list. I decided to use a dictionary where the object ids are the keys. In this way, we can make sure that we will never have duplicate entries.
At the beginning of the execution, the program retrieves the current objects. Then we use the live query events to keep this list updated. I use to retrieve the initial set of objects in the open event, so we can make sure that we are now really listening to the live query and we will not lose any information. I did that simply executing the query. For that to work, I had to turn the callback async and transform the returned array into the dictionary of objects.
In the create event, I added the object to the dictionary. In the updated event, I updated the object. In the enter event, I added again. Finally, I removed the object in the leave and delete the event. I didn’t do anything in the close event since, when the connection is lost, the Parse JS SDK tries to reconnect automatically, and if successful, it will fire the open event again, and therefore retrieve the updated list of objects. I also created a print function that prints out the objects after each of the events. My code at the end became like this:
Ok, at this point I was ready. I executed the program to see it in action.
$ node index.js
Our first event showed up!
subscription opened
This is the live updated list of not closed todos
{ title: 'Learn Live Query',
createdAt: '2020-09-24T06:59:50.135Z',
updatedAt: '2020-09-24T06:59:53.047Z',
isClosed: false,
objectId: 'DO6hiOriQB' }
Then I created another object and saw the create event in action.
todo YCVLvtzNdq created
This is the live updated list of not closed todos
{ title: 'Learn Live Query',
createdAt: '2020-09-24T06:59:50.135Z',
updatedAt: '2020-09-24T06:59:53.047Z',
isClosed: false,
objectId: 'DO6hiOriQB' }
{ title: 'Create Live Query Video',
createdAt: '2020-09-28T08:17:56.997Z',
updatedAt: '2020-09-28T08:17:56.997Z'
But I accidentally left the isClosed
field undefined. Then I set it to false. The update event was fired. This object was already in the results of the query and continued in the results. That’s why I had the update event fired.
todo YCVLvtzNdq updated
This is the live updated list of not closed todos
{ title: 'Learn Live Query',
createdAt: '2020-09-24T06:59:50.135Z',
updatedAt: '2020-09-24T06:59:53.047Z',
isClosed: false,
objectId: 'DO6hiOriQB' }
{ title: 'Create Live Query Video',
createdAt: '2020-09-28T08:17:56.997Z',
updatedAt: '2020-09-28T08:19:03.247Z',
isClosed: false,
objectId: 'YCVLvtzNdq' }
Then I switched the todo that was closed to the not closed state. Instead of the update event, I received the enter event. This object was not a match for the query before, but it became a match after the update.
todo XEbAoalthk entered
This is the live updated list of not closed todos
{ title: 'Learn Live Query',
createdAt: '2020-09-24T06:59:50.135Z',
updatedAt: '2020-09-24T06:59:53.047Z',
isClosed: false,
objectId: 'DO6hiOriQB' }
{ title: 'Create Live Query Video',
createdAt: '2020-09-28T08:17:56.997Z',
updatedAt: '2020-09-28T08:19:03.247Z',
isClosed: false,
objectId: 'YCVLvtzNdq' }
{ title: 'Learn Parse',
createdAt: '2020-09-24T06:59:37.449Z',
updatedAt: '2020-09-28T08:20:55.875Z',
isClosed: false,
objectId: 'XEbAoalthk' }
I marked it as closed again and saw the leave event since we are talking about an object that was a match but became not a match anymore.
todo XEbAoalthk left
This is the live updated list of not closed todos
{ title: 'Learn Live Query',
createdAt: '2020-09-24T06:59:50.135Z',
updatedAt: '2020-09-24T06:59:53.047Z',
isClosed: false,
objectId: 'DO6hiOriQB' }
{ title: 'Create Live Query Video',
createdAt: '2020-09-28T08:17:56.997Z',
updatedAt: '2020-09-28T08:19:03.247Z',
isClosed: false,
objectId: 'YCVLvtzNdq' }
Then I deleted an object and got the delete event.
todo YCVLvtzNdq deleted
This is the live updated list of not closed todos
{ title: 'Learn Live Query',
createdAt: '2020-09-24T06:59:50.135Z',
updatedAt: '2020-09-24T06:59:53.047Z',
isClosed: false,
objectId: 'DO6hiOriQB' }
Note that no event would be fired if I had created, updated, or deleted an object that was not a match for the query. Finally, I simulated the subscription being closed by the server. I did that by restarting my Parse app at Back4App. I saw there were some close events. The Parse JS SDK tried to connect multiple times to the server while it was still restarting, and finally, it was able to open the subscription and retrieve the current objects again. That’s it! I hope this article can help you to master the Parse Live Query.
You can find the complete project in the link below:
https://github.com/back4app/js-demos/tree/master/live-query
Clone the database schema at Live Query Demo Public Database on Back4App Hub.
If you have any questions, please let me know in any of the Parse or Back4App community channels and I will be glad to help.