Understanding Realm FlexibleSync

I am trying to understand the logic behind Subscriptions and query fields in FlexibleSync, as I understand, these are needed to “listen” to changes, so that any change done in that collection will be synced, my predicament however is what kind of subscriptions must I have if I want to listen to all changes?!

I tried to configure the app with the following, and as I wrote in adjacent thread, although it worked once, it never worked again and now I am doubting maybe it was because of how I configured the subscriptions…


   _realm.Subscriptions.Update(() =>
            {
                _realm.Subscriptions.Add(_realm.All<EntryEntity>());
                _realm.Subscriptions.Add(_realm.All<LanguageEntity>());
                _realm.Subscriptions.Add(_realm.All<PhraseEntity>());
                _realm.Subscriptions.Add(_realm.All<SourceEntity>());
                _realm.Subscriptions.Add(_realm.All<TranslationEntity>());
                _realm.Subscriptions.Add(_realm.All<UserEntity>());
                _realm.Subscriptions.Add(_realm.All<WordEntity>());
            });

Is this way of configuring, i.e. adding everything to subscriptions is ok? If so, why it’s not a normal behavior, i.e. why would you even need to configure subscriptions if realm can handle all object changes for all objects? If it’s not ok, then how else should I have configured them to listen to changes to any of those entities, regardless of who made the changes and on which field?

Thank you.

Hi @Movsar_Bekaev. The way that you’re setting up the subscription seems to be fine, so that should work. If it doesn’t, then we need to investigate what’s happening.

Regarding the idea behind flexible sync… The main idea here is that you subscribe only to the objects that you are interested into. Imagine having a todo application with millions of users. Most probably you don’t need to sync all todo items for all users on all devices, because it will be useless, and there won’t be enough space on the device probably. In this case you’d probably add a subscription to sync only the todo items for the current user. This is obviously a simple case, but I hope that you can get the point.
Overall, the idea here is to sync only the objects that are relevant to the current user at a specific time.

Just to add up on that. When you are developing the app probably it’s fine to get all data downloaded, but in a production app this would probably be too much data downloaded, and unnecessary.

1 Like

I see, so my idea was to ship the local database file to platforms, to reduce first start and then update it because I am building a dictionary app and all the entries must be up to date regardless of who made the changes and who’s viewing them. Is that still going to be a significant problem as to speed?

Also, when exactly should I use

 await _realm.Subscriptions.WaitForSynchronizationAsync();

As I think I should use it right after start, after acquiring Realm instance and setting up Subscriptions - to download external changes and after I make changes to sync, am I correct?

The last one - should I use any other methods like those in SyncSession - WaitForDownload or WaitForUpload etc?

My original problem is described here btw, please take a look if you get the chance. This is a blocker for me and I am not even trying to make this work now, just want to understand though, for future tries :slight_smile:

Thank you

Your use case doesn’t seem problematic for sync. You will start to encounter issues only if the amount of data that needs to be synced from/to the device is too big. If you need to move around only few items it shouldn’t be a problem.

await _realm.Subscriptions.WaitForSynchronizationAsync() is a method that returns when the subscriptions have been synchronized, and all the relevant data has been downloaded on the device. It is not mandatory to call this method, as those changes will happen automatically anyways on a background thread, but you have no guarantees about the timing exactly. It’s definitely a good practice to call it after you’re changing subscriptions though, as it will ensure that the device has all the relevant data.

Regarding WaitForDownload and WaitForUpload, I would say that most of the times you don’t need them. Those methods return when (respectively) all the sync data has been dowloaded or uploaded from/to the device to the sync server. In the majority of cases you don’t need to do that manually, as the data is synced automatically on a background thread. It could be useful in some specific instances, in which you want to be sure that data has been downloaded/uploaded.
For example, you could call WaitForUpload when the user logs out from the application, to be sure that all the data available has been synced.

Regarding your original problem, I didn’t give a look yet, but I’ll do it soon.

1 Like

Thank you, this is very helpful, I spent 4 days digging into official documentation but your two posts gave more information :slight_smile:

I’d like to know also:

  1. Do we need to remove and add anew Subscriptions each time we get Realm instance? I mean, in async/await, you have to get Realm instance each time it’s needed in a new task, so, does this affect Subscriptions? If I add them as shown before on app start, do I need to add them again each time I require Realm Instance?

  2. Coming back to query fields, if I am adding subscriptions like I do with

    _realm.Subscriptions.Add(_realm.All<EntryEntity>());
    

    Will it use _id as default query field? or they don’t matter when subscribing to whole collection

  3. Do I need partition_id field on my models, when using FlexibleSync (I thought it’s obviously “no”, but in quick start example it asks you to specify them no matter which method is chosen - maybe it’s just not updated?)

Thank you so much!

  1. No, you don’t need to, the subscriptions are saved in the db itself. What you could do is to use PopulateInitialSubscriptions as shown in the docs. With that, the subscriptions are added only when the realm is created and opened for the first time. Regarding that… a good pattern is probably to create something like a RealmService in your project, so you can create the Realm with the same configuration every time and forget about it. Something like
    public static class RealmService
    {
        private const string appId = "****";

        private static Realms.Sync.App app;

        public static void Init()
        {
            app = Realms.Sync.App.Create(appId);
        }

        public static Realm GetRealm()
        {
            var config = new FlexibleSyncConfiguration(app.CurrentUser)
            {
                PopulateInitialSubscriptions = (realm) =>
                {
....
                    realm.Subscriptions.Add(query);
                }
            };

            return Realm.GetInstance(config);
        }

....
}
  1. In this case there is no need to specify the query field, as you said, as you’re getting the whole collection
  2. You do not need _id on your models, but that’s the default query field with Flexible Sync and you cannot remove, so it will be there even if you don’t need it :smile:

Also, regarding your other issue, it will be better if you provide us with your client logs and also the app id, so that we can take a look at the server logs and see what’s happening. If you do so, it makes sense to do in the other thread though, otherwise it’s complicated to follow the whole conversation :wink: . Also, if you prefer not to share your appId (or even the whole project if you want), we can provide a confidential channel where you can send that info (or the project).

1 Like

Thank you! Regarding the other issue - I will post in that thread once I set it up once again.
I’ll share the app id - no problem with that.

You’re awesome, have a great day!

What’s the best practice if you have 100k users?

If you have 100k users you can’t obviously sync data for all users for all device. In that case you need to find a way to identify which data belongs to which user, for example, and sync only that. Most times that can be, for instance, adding a UserId variable to che classes and sync on that with something like UserId == currentUserId.

1 Like

And if I want to search for other users in this case, I’d do it server side or with a function?

@Alexandar_Dimcevski You could do something as described here. By the way, if you have additional questions/doubts I would suggest to open a new topic, otherwise it gets confusing to follow along.

1 Like

Got it. Sorry for missing threads

I’d like to clarify what is expected to happen here, now I’ve spent a while getting my head around FlexibleSync.

Seems @Movsar_Bekaev wants to

  1. distribute his app including the known database (lets say with 100K objects) and
  2. expects a tiny number of updates from any user which
  3. should be broadcast to all users

So the big question is - can you distribute a copy of a Flexible Sync Realm?

If yes, then his subscriptions will work fine, there will be some initial reconciliation and it will be only new/changed entries going across then network.

If no, there are two choices:

  1. all data needs to be downloaded by all users on initially running the app, or
  2. use a local Realm as the main source of lookup data (which is bundled with the app) and FlexibleSync only to get changes which are copied by the app into the local Realm.