2

I am using realm-js to store data for a user on their device with React Native and there is a point in the workflow where I would like to copy all of the data in the local realm into a synced realm (to persist on ROS). I am running into an issue where in our schemas we have created pseudo relationships by adding a property referencing one object into another object and vice-versa and in doing so we have created circular data structures.

This has actually worked fine in the app but now we are attempting to copy the data from the local realm into the synced realm and it crashes, seemingly, because of the circular references.

For example the schemas look something like this.

class Person extends Realm.Object {}
Person.schema = {
  name: 'Person',
  properties: {
    firstName: {
      type: 'string',
      optional: true,
    },
    staffAccount: {
      type: 'StaffAccount'
    },
  },
};

class StaffAccount extends Realm.Object {}
StaffAccount.schema = {
  name: 'StaffAccount',
  properties: {
    id: {
      type: 'string',
    },
    people: {
      type: 'list',
      objectType: 'Person',
    },
  },
};

In this example when creating a Person you would define a staffAccount property and that staff account property would have a people property which has a list of the people with that staff account and in that list there would be the person initial person in the Person schema.

Is there any way of getting around this problem when copying data from one realm to another?

bdash
  • 18,110
  • 1
  • 59
  • 91
jasonmerino
  • 3,220
  • 1
  • 21
  • 38

1 Answers1

2

Take a look at this code that takes a local .realm file and copies it into a remote synced Realm. The code could be simplified since it looks like you already know the schema - this code dynamically loads the schema. Hope it helps

// Copy local realm to ROS

const Realm = require('realm');


// UPDATE THESE
const realm_server = 'localhost:9080';

const source_realm_path = './localRealm.realm'; // path on disk
const target_realm_path = '/syncRealm'; // path on server


function copyObject(obj, objSchema, targetRealm) {
    const copy = {};
    for (var key in objSchema.properties) {
        const prop = objSchema.properties[key];
        if (prop.type == 'list') {
            const propObjSchema = targetRealm.schema.find((s) => s.name == prop.objectType)
            copy[key] = obj[key].map((obj) => copyObject(obj, propObjSchema, targetRealm))
        }
        else if (prop.type == 'object') {
            const propObjSchema = targetRealm.schema.find((s) => s.name == prop.objectType)
            copy[key] = obj[key] ? copyObject(obj[key], propObjSchema, targetRealm) : obj[key];
        }
        else {
            copy[key] = obj[key];
        }
    }
    return copy;
}

function getMatchingObjectInOtherRealm(sourceObj, source_realm, target_realm, class_name) {
    const allObjects = source_realm.objects(class_name);
    const ndx = allObjects.indexOf(sourceObj);

    // Get object on same position in target realm
    return target_realm.objects(class_name)[ndx];
}

function addLinksToObject(sourceObj, targetObj, objSchema, source_realm, target_realm) {
    for (var key in objSchema.properties) {
        const prop = objSchema.properties[key];
        if (prop.hasOwnProperty('objectType')) {
            if (prop['type'] == "list") {
                var targetList = targetObj[key];
                sourceObj[key].forEach((linkedObj) => {
                    const obj = getMatchingObjectInOtherRealm(linkedObj, source_realm, target_realm, prop.objectType);
                    targetList.push(obj);
                });
            }
            else {
                // Find the position of the linked object
                const linkedObj = sourceObj[key];
                if (linkedObj === null) {
                    continue;
                }

                // Set link to object on same position in target realm
                targetObj[key] = getMatchingObjectInOtherRealm(linkedObj, source_realm, target_realm, prop.objectType);
            }
        }
    }
}

function copyRealm(user, local_realm_path, remote_realm_url) {
    // Open the local realm
    const source_realm =  new Realm({path: local_realm_path});

    // Create the new realm (with same schema as the source)
    const target_realm = new Realm({
        sync: {
            user: user,
            url:  remote_realm_url,
        },
        schema: require('./realmmodels')
    });

    // Copy all objects but ignore links for now
    target_realm.schema.forEach((objSchema) => {
        console.log("copying objects:", objSchema['name']);
        const allObjects = source_realm.objects(objSchema['name']);
        target_realm.write(() => 
          allObjects.forEach((obj) => {
              // Add this object to the target realm
                  target_realm.create(objSchema.name, copyObject(obj, objSchema, target_realm), true)
        }));
    });
}

const remote_realm_url = "realm://" + realm_server + target_realm_path;
copyRealm(Realm.Sync.User.adminUser("ADMIN_TOKEN"), 
    source_realm_path, remote_realm_url);
console.log("done");
Ian Ward
  • 66
  • 2