Device Sync with roles that depend on user custom data is not triggered immediately

We have a Role for a collection Place that depends on user custom data, so something similar to:

{
  "roles": [
    {
      "name": "cityAccessRule",
      "apply_when": {},
      "document_filters": {
        "write": {
          "city": {
            "$in": "%%user.custom_data.cities"
          }
        },
        "read": {
          "city": {
            "$in": "%%user.custom_data.cities"
          }
        }
      },
      "read": true,
      "write": true,
      "insert": true,
      "delete": true,
      "search": true
    }
  ]
}

We are updating the custom user data collection in a React Native app and calling refresh as doc:

      realm.write(() => {
        customUserData.cities = cities;
      });
      await user.refreshCustomData()

As soon as the user custom data is updated, we would expect to sync down the documents in the collection Place that passes successfully the role. But this is not the case, user needs to to kill the app and open again to trigger a new sync and see the expected Place documents.

All data seems correct on the server side (Dedicated M10) for the CustomUserData collection and UserSettings in AppSettings has correct configs for userId and Creation Function is working correctly. As well the connection between userId (CustomUserData collection) and the user.Id (User collection from Atlas) seems correct, as it is fetching correctly the expected documents, but only after the user restarts the app.

We performed some tests and issue seems to be connected with the user custom data update across the Mongo Atlas environment. Because if we use a static value for the Role comparison the sync is immediate as soon as the condition passes. But if it depends on a value from custom user data, then the sync it’s not immediate.

If there is any workaround would be appreciated, such as forcing the sync down on mobile side when we have the data updated.

Hello @Ampop_Dev ,

Welcome to the MongoDB Community , :wave:

Thank you for raising your concerns. The behavior you observed in the application is as expected. Changes in custom user data are not picked up until the sync session restarts.

You can find out more details in the Realm newsletter shared last month with some community conversations linked to the post.

I hope this was helpful. Let me know if I can help you with anything else.

Cheers, :performing_arts:
henna

@henna.s thank you for your answer and is there a way to restart the sync session without restarting the app?

Hi, yes most of the SDK’s have an API to pause and resume the sync session (https://www.mongodb.com/docs/realm/sdk/react-native/sync-data/manage-sync-session/#pause-or-resume-a-sync-session). This should handle the refresh properly.

One way we suggest temporarily getting around this restriction is to sync down the custom user data object (many of our customers do this in order to make changes to it). Then you can setup progress listeners on the object to be notified whenever it changes.

Best,
Tyler

1 Like

@Tyler_Kaye thanks yes that works, calling pause then resume forces the sync:

await user.refreshCustomData();
realm.syncSession.pause();
realm.syncSession.resume();

But it might be worth to prioritize automatic trigger of a sync if the custom user data changes and is a condition in roles for a collection. But thanks for the workaround, have great day!

1 Like

@Tyler_Kaye There is another scenario in which the pause + start does not help, only killing and restarting app that we noticed now. I’ll try to provide replication steps:

  1. Login anonymously
const credentials = Realm.Credentials.anonymous();
await app.logIn(credentials);
  1. Register a new user, will be send confirmation email:
await app.emailPasswordAuth.registerUser(
  {
    email,
    password,
  },
);
  1. Confirm user with email and login with new user
await app.emailPasswordAuth.confirmUser({
  token,
  tokenId,
});
const credentials = Realm.Credentials.emailPassword(
  email,
  password,
);
await app.logIn(credentials);
  1. The CustomUserData subscriptions does not work, currentCustomUserData is undefined, restarting app fixes sync.
const customUserQuery = useQuery(CustomUserData);
const user = useUser();

useEffect(() => {
  realm.subscriptions.update(mutableSubs => {
    mutableSubs.add(realm.objects(CustomUserData));
  });
}, [realm]);

const currentCustomUserData: CustomUserData = useMemo(() => {
  if (user?.id) {
    const currentUser = customUserQuery.filtered(`userId == '${user.id}'`);
    return currentUser?.[0];
  }
}, [customUserQuery, user.id])

console.log('currentCustomUserData', currentCustomUserData?.cities) // Is undefined, restarting app necessary

We noticed that user.id is correctly updated with new user id, but the customUserQuery does not return the document. We confirmed on backend side and the value this CustomUserData document for this new userId is on server, so issue is only with sync.

Do you have any workaround to restart the collection subscription? We tried remove + add:

realm.subscriptions.update(mutableSubs => {
  mutableSubs.remove(realm.objects(CustomUserData));
  mutableSubs.add(realm.objects(CustomUserData));
});

But we get unhandled promise rejection:

{
  "errorCode": "OperationAborted",
  "message": "Sync session became inactive",
}

@Tyler_Kaye is there any workaround for this? Pause + Start does not help, only killing and restarting app. It seems that useRealm hook are not being updated when we have new user is being logged in there is a set of rules using custom user data. Killing and restarting works correctly, so this is an issue only with the sync session getting lost when the user changes.

@Tyler_Kaye we are still blocked and new version 12.0.0 of realm JS does not fix this. The reproduction steps are simple, please let us know how to proceed:

  1. Login anonymously
  2. Update CustomUserData that has param that a sync Rule depends on
  3. Login with new user by email/gmail/apple
  4. Update CustomUserData with new param

Example of Rule:

{
  "roles": [
    {
      "name": "CustomUserDataRule",
      "apply_when": {},
      "document_filters": {
        "write": {
          "foo": "%%user.custom_data.foo"
        },
        "read": {
          "foo": "%%user.custom_data.foo"
        },
      },
      "read": true,
      "write": true,
      "insert": true,
      "delete": true,
      "search": true
    }
  ]
}

The sync session is not updated with the new CustomUserData from the new logged in user. If we restart the app, everything works correctly and the new user can update the CustomUserData and the sync session is correctly refreshed.

There is a serious limitation on the sync session if you log in anonymously then with another user without restarting app. What is the recommended way of refreshing the sync session when a new user logs in? We tried methods from doc (pause, start) but it does not help: https://www.mongodb.com/docs/realm/sdk/react-native/sync-data/manage-sync-session/