How can I sync a subset of local documents with flexible sync?

Hi,

I’m working on a React Native Realm application and for our use case we don’t want to sync documents until they are “ready” (which involves some user interaction). I was hoping that I could use a sync property along with a subscription that looks like sync == true and then keep documents in the local realm until they are ready to be synced, but I end up with SyncError: Client attempted a write that is outside of permissions or query filters; it has been reverted.

What is the best way to achieve what I’m looking for?

Hi @Dave_Keen,

Yes, that’s by design: you can’t write documents into the database that don’t match your subscription, as Device Sync will try to maintain the content of your local DB consistent with the backend. There can be different workarounds, for example, you could open a second, local-only realm where you keep the unfinished document. When the document is ready to be synched, you can copy it to the synched realm, and remove it from the local one, i.e. something like

let realmLocal;
let realmSynched;

try {
  realmLocal = new Realm(localConfig);
  realmSynched =  await Realm.open(synchedConfig);
} catch (err) {
  //… handle error
}

let obj;
let objCopy = {};

realmLocal.write(() => {
  obj = realmLocal.create("TestData", { _id: new ObjectId(), … });
});

// … when document is ready…
realmSynched.write(() => {
  objCopy = realmSynched.create("TestData", obj);
  // …change the fields to match synched requirements…
});

// … and remove the local temporary copy
realmLocal.write(() => {
  realmLocal.delete(obj);
  obj = null;
});

Thanks for your quick reply! The documents I am creating may have relationships (one to one and one to many) to existing documents in the synced database. Is that going to cause any problems?

No, relationship won’t work across realms, you may need to use placeholders while the document isn’t finalised, and set the exact relationships when you’re ready to write into the synched realm.

Can you please describe the use case, why shouldn’t the document be synched from the beginning? If the issue is about different access, you may be able to simplify things, for example, by defining different access roles, before and after finalisation, and still keep the synching mechanism happy…

I’m making a note taking app, where the note is a document and can have links to various other documents. The user enters their note, then have a UI where they can link the note the the other documents. Finally they press “done” and the note gets synced. We don’t want to sync anything until this point for reasons of privacy and bandwidth (the note can potentially have a lot of links to other documents which get pruned after the UI interaction).

Currently I’m building the note in a transaction, using toJSON() to detach it from the realm and then cancelling the transaction. This sort of works but feels pretty hacky.

I originally tried to build the document as a plain object but this proved tricky with Typescript as the class already inherits from React.Object so I couldn’t use the class without Realm noticing. However, I recently discovered that I can point the generic of React.Object to something other than the class itself, so maybe that will help to decouple the type definition and the Realm object (I haven’t tried this yet). I also wasn’t quite sure what will happen with relationships and collections when building a plain object and passing it into realm.create.

All advice appreciated!

Hello, @Dave_Keen,

Thanks for sharing your use case.

Finally they press “done” and the note gets synced. We don’t want to sync anything until this point for reasons of privacy and bandwidth (the note can potentially have a lot of links to other documents which get pruned after the UI interaction).

You can have more control over privacy if you define document or even field-level permissions. Please follow MongoDB documentation on Role-based Permissions. Your feedback on how this can be made more clear is appreciated.

I also wasn’t quite sure what will happen with relationships and collections when building a plain object and passing it into realm.create .

The relationships work within the same realm. At this moment, the only alternate is to have separate local v/s sync realms or create managed v/s unmanaged objects as you suggested.

Let us know if you try using realm.create and we will go forward from there.

Cheers, :performing_arts:
henna

One common pattern for this I have seen, is to have a draft = true property on the objects that are work-in-progress. This obviously does not reduce the bandwidth usage, but it gives a lot of other benefits.

It allows other devices using the same data (like the users other iPad, etc) to either filter out the drafts, or even allow the user to continue the work as they move between devices, and it also ensures that the data is backed up in case something happens to the device before the draft version is published.