@Maxime_Boceno
I’m rewriting this in C# right now, but here’s the solution to this in React Native:
Your custom data documents contain an array of office objects, each with an “officeId” property, and to my understanding the goal is to use this array to determine document access in Realm Flex Sync. The current attempt to use “$in: user.custom_data.offices.officeId” as a Realm rule is not working because the “$in” operator expects an array of IDs.
The suggested solution is to flatten the “offices” field to be an array of IDs instead of an array of objects. This can be done by changing the user data model to look like this:
{
"offices": [1, 2]
}
To implement this solution in React Native for iOS, you can use the Realm SDK for React Native to read and update user data. Here is some example code:
import Realm from 'realm';
// Define the User schema
const UserSchema = {
name: 'User',
properties: {
_id: 'objectId',
offices: 'int[]',
},
};
// Open a Realm with the User schema
const realm = await Realm.open({
schema: [UserSchema],
sync: {
user: user,
partitionValue: 'somePartitionValue',
existingRealmFileBehavior: 'openLocal',
},
});
// Update a user's offices array
realm.write(() => {
const user = realm.objectForPrimaryKey('User', 'someUserId');
user.offices = [1, 2];
});
// Query for all documents where OfficeId is in the user's offices array
const results = realm.objects('SomeCollection').filtered('OfficeId IN $0', [1, 2]);
This code opens a Realm with a User schema that includes an “offices” field of type “int” (an array of integers). It then updates a user’s “offices” array and queries for all documents in “SomeCollection” where the “OfficeId” field is in the user’s “offices” array.
I’ll update in about a half hour or so with another explanation of how to implement this in C# to give you a more clear idea of how this works from different angles.
Here’s the update with csharp, I kept screwing up the error handling as it wouldn’t compile right because my IDE kept trying to pull from another project I have running.
// Define your Office class to match the structure of your Office documents
public class Office : RealmObject
{
[PrimaryKey]
[MapTo("_id")]
public ObjectId Id { get; set; }
[MapTo("officeId")]
public int OfficeId { get; set; }
[MapTo("name")]
public string Name { get; set; }
}
// Create a MongoDB Realm client
var realmApp = new App(new AppConfiguration
{
AppId = "my-app-id",
JwtAuthProvider = new JwtAuthProviderClient(JwtAuthProviderClient.DefaultScheme, () => "my-jwt-token")
});
// Log in to the app using username/password
var user = await realmApp.LogInAsync(new Credentials.UsernamePassword("user@example.com", "password"));
// Get the user's custom data
var customUserData = user.GetCustomData();
// Get the array of office IDs from the user's custom data
var officeIds = customUserData["offices"].AsBsonArray.Select(office => office["officeId"].ToInt32());
// Configure flexible sync
var syncConfig = new SyncConfiguration("my-partition-value")
{
BsonSchema = RealmSchemas.Register<Office>()
};
var syncClient = realmApp.GetSyncClient(user);
var syncSession = await syncClient.StartSessionAsync();
var syncRealm = await syncClient.OpenRealmAsync(syncConfig);
var officeCollection = syncRealm.GetCollection<Office>();
// Sync the Office collection
var query = officeCollection.Where(office => officeIds.Contains(office.OfficeId));
var subscription = query.Subscribe();
var result = await subscription.WaitForCompletionAsync();
// Handle errors
if (result.ErrorCode == ErrorCode.SessionClosed)
{
// Handle session closed
}
else if (result.ErrorCode == ErrorCode.ClientReset)
{
var clientReset = result.ClientReset;
// Handle the client reset
if (clientReset.InitiatedBy == ClientReset.InitiatedByServer)
{
// Delete any unsynced changes
var unsyncedChanges = clientReset.GetRecoveredChanges<Office>();
foreach (var change in unsyncedChanges)
{
officeCollection.Write(() =>
{
if (change.OperationType == ChangeOperationType.Delete)
{
var obj = officeCollection.Find(change.DocumentKey);
obj?.Delete();
}
else
{
var bsonDoc = change.FullDocument;
officeCollection.Add(bsonDoc.ToObject<Office>());
}
});
}
// Restart the sync
await syncSession.EndSessionAsync();
syncRealm.Dispose();
syncRealm = await syncClient.OpenRealmAsync(syncConfig);
officeCollection = syncRealm.GetCollection<Office>();
query = officeCollection.Where(office => officeIds.Contains(office.OfficeId));
subscription = query.Subscribe();
result = await subscription.WaitForCompletionAsync();
}
}
// Access the synced Office documents
var offices = officeCollection.ToList();
// End the sync session
await syncSession.EndSessionAsync();
NOTE: The updated code checks for the SessionClosed
error in addition to the ClientReset
error. In the case of a ClientReset
, the code now deletes any unsynced changes and restarts the sync. The updated code also uses a try...catch
block around the code that accesses the synced officeCollection
to handle any exceptions that might occur.