Trigger on updates to document made while offline

I have a Realm Sync app that works both online and offline. When offline, a user would insert a ‘record’ document. Then later update a particular field (matrix.items) of that document (while still offline). When connectivity is restored with Atlas, it appears that the only changeset that occurs is an insert:

"record": {
    "inserted": [
      "626fa2578c3afa5f231b8bbe"
    ]
  }

I have a trigger on the records collection that listens to updates to the matrix.items field. This works fine when the user is updating the document while online (changeset is:

"record": {
    "updated": [
      "626fa2578c3afa5f231b8bbe"
    ]
  }

)

I suspect that Realm Sync may bulk operations together to limit data transfer and as such, when connectivity is restored, it only sends one inserted document containing all the changes made while offline.

So I added a trigger that listens to inserts in the records collection. But the fullDocument received by this trigger does not contain the matrix.items field (it is undefined), even though the synced document in Atlas does contain the matrix.items field.

Should my trigger on inserted records not receive a fullDocument containing all the updates to the document made while offline? If not, how do I listen to changes to the record document that were made offline so my trigger can fire?

Hi. You are correct that Realm Sync batches many operations together when possible, and doing so lets us achieve much better performance. I suspect the reason you are not seeing the “updates” to the list is that they may be showing up as Replace events on the change stream. Some of the operations that we perform on lists can only be done using MongoDB Update Pipelines (https://www.mongodb.com/docs/manual/tutorial/update-documents-with-aggregation-pipeline/). These operations result in full-document replaces, so they will appear in the Trigger/ChangeStream as a Replace event.

Please let me know if that is the case,
Tyler

2 Likes

It worked! :tada: Thanks a lot @Tyler_Kaye for being so quick to help!

2 Likes

Of course glad that we could help.

Have a nice day,
Tyler

Hi @Tyler_Kaye, actually I may have been a bit quick to celebrate here. I’m not sure it has worked. I’ve put a trigger for ‘replace’ events and the records collection but it doesn’t get triggered when a document gets synced (when connectivity is restored). Any idea what’s going on?

Hi, apologies if I was not clear, but I think that in order to safely capture all events you will need to enable a trigger for “insert”, “update”, and “replace” events.

Hi @Tyler_Kaye,

So I’ve been conducting some further tests and it appears that my issue is not with the type of event the trigger listens to but the match expression used to fire it.

I have a handleRecordUpdated trigger (for update events) with a match expression so that it only gets triggered when the matrix.items field is updated. That’s to prevent many unnecessary trigger fires when the user updates other fields of the record.

I’ve noticed that, whether the update occurred offline or online, the update event always contains ‘matrix.items’ in updateDescription.updatedFields. So that’s the field I want to write my match expression on.

For info, that’s what my initial issue was: I was using {"updateDescription.updatedFields.matrix":{"$exists":true}} as my match expression but when updated offline, this evaluates to false.

So my match expression is now: {"updateDescription.updatedFields.matrix.items":{"$exists":true}}. But this doesn’t seem to work (maybe because matrix.items is an array?). The trigger doesn’t fire anymore.

Here is a screenshot of an example matrix field in a record:
Screenshot 2022-05-03 at 10.56.30

Any idea what’s wrong with my match expression?

Hi, the first thing that comes to mind is that updateDescription only exists for Update events, so replace events will now all be filtered out.

As for how to go about fixing this, I find that with all match expression issues the best way to go about it is to log the change events being made so that you can physically see that they look like. MongoDB change events can be a bit hard to think about, so I would reccomend setting up a trigger without any match expression and having the function code just be “console.log(EJSON.Stringify(changeEvent))”. Then perhaps it will become apparant why your match expression is not firing. If its still not clear, then plase post a sampling of them here and I can help out!

Thanks,
Tyler

Hi @Tyler_Kaye ,
As you suggested, I’ve created a test trigger listening to insert, update and replace events (and no match expression).

When I insert a record while offline then update record.matrix.items while still offline and finally restore connectivity, I get the following changeEvents on the trigger:

  • insert
  • update with “updatedFields: [“matrix.items”]”

I don’t get any replace events.

I’ve seen in another post that people have had issues in the past with match expressions on nested arrays. Would there be a way around? Is there a way to write a match expression where at least one element in updatedFields startsWith the word ‘matrix’?

Thanks!