Hi,
I’m working on a Flutter app that tracks matches for an amateur, nationwide sports league. I’m using flexible sync and the main tables I have are:
User : Read/write own role.
Player (Read all role. Stores public info such as name, image url, etc.)
Match (Read/write own roles. Stores both player IDs and match details)
I have all of this working except I’m wondering if my approach is right when it comes to syncing players.
Right now each User is subscribed to all matches they have played in, with player 1 being the “owner” in terms of write permissions. At startup I update subscriptions. I then build an opponent list based on the current user’s matches and manually subscribe to each opponent so they are synced locally. This allows me to provide a list view with all of their matches and opponent’s info…even when offline. With that setup, I’ll have to update this subscription list every time a match is created or deleted to keep things in sync. However, from what I’ve read, you shouldn’t update subscriptions often due to a performance hit. I’m not sure what that “hit” will be.
A couple of other ways I’ve considered:
-
Have each user maintain a list of players that gets updated when a new match is created. Then under read roles, call a server function to allow/disallow reading of only the players a user has played against. Drawback: That list is essentially unbounded and could get quite large over time. Otherwise, I think this would work but I haven’t tried it yet.
-
Embed (duplicate) player data in each match. Drawback: duplication of data that won’t update when the player changes their name, image, etc.
-
Syncing with all players. Drawback: That could be thousands of players over time so bandwidth, space and performance concerns.
Is there a 4th option?
The bottom line is that I want each user to have their matches and opponents they played in those matches subscribed to in the most efficient way so that those documents are available to them even if they are offline.
Any tips would be appreciated!
My existing code is below if it’s useful to see:
Future _updateSubscriptions(User user) async {
// subscribe to the current user's Player document
await realm!.query<models.Player>("_id == oid(${user.id})").subscribe(
name: 'player',
waitForSyncMode: WaitForSyncMode.firstTime,
update: true);
// subscribe to all matches that the current user has played in
await realm!.all<models.Match>().subscribe(name: 'matches', update: true);
// build a list of players the current user has had matches with
List<ObjectId> matchplayers = [];
for (models.Match match in realm!.all<models.Match>()) {
if (!matchplayers.contains(match.p1_id;
)) {
matchplayers.add(match.p1_id;
);
}
if (!matchplayers.contains(match.p2_id)) {
match.players.add(match.p2_id);
}
}
matchplayers.remove(ObjectId.fromHexString(
user.id)); // remove the current user's player from the list since we've already subscribed to it above
// remove subscriptions for players the current user no longer has matches with
realm!.subscriptions.update((subscriptions) {
var playersubs =
subscriptions.where((element) => element.name!.startsWith('p='));
for (Subscription sub in playersubs) {
String userid = sub.name!.substring(2);
if (!matchplayers.contains(ObjectId.fromHexString(userid))) {
subscriptions.remove(sub);
}
}
});
// add subscriptions for players we have matches with but aren't subscribed to
for (ObjectId id in matchplayers) {
await realm!.query<models.Player>("_id == oid($id)").subscribe(
name: "p=$id",
waitForSyncMode: WaitForSyncMode.firstTime,
update: true);
}
)