Get 0 objects with partial sync


#1

Hello.

Could someone explain how to work with partial mode? There is something unclear for me.
I wrote 2 scripts: “client” and “server”. In general, scripts are the same. In the server script - I push some data (with “test-admin” user). In the “client” script - I make a query to get data (with “test” user), but always got 0 objects.

I am working with realm-cloud. When I tried to play with “open”/“new Realm” - sometimes I got results in the query. Looks like each script creates his own realm. But when I open realm via Realm Studio I see 2 users in the table “__Users”, they both have access to data (role - everybody)

What is the proper way to work with partial sync? I also tried to make the query with setTimeout 5 second.
What am I missing here?

Sorry, several days ago I created another topic, but there was another issue and workaround was found for it.

Сode is below

“Server”:

const faker = require('faker');
const Realm = require('realm');
const fs = require('fs');

const totalTickers = 100;
const USERNAME = "test-admin";
const PASSWORD = "12345678";
const SERVER = "some server url"

const TickerSchema = {
    name: 'Ticker',
    primaryKey: 'tickerSymbol',
    properties: {
        tickerSymbol: {type: 'string', optional: false},
        price: {type: 'int', optional: false},
        companyName: {type: 'string', optional: false},
        ch: {type: 'Ticker1', default: null}
    }
};

const token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJSZWFsbSIsIk5vdGlmaWVyIjp0cnVlLCJTeW5jIjp0cnVlLCJpYXQiOjE1MTI2NTY3Nzh9.iKhiNXtCT5HtEZc0SKlNnZOaCU8XSpbVYCyGm6RKgw3_tQogN5Ln5oG7bfFTBNJKi0zbjKVJcFGtBhxus27BWYgdVUTH_AHswfEY4BuaRKWK1dvUPn1mx7Fp7lQHnCPwp_nvhaqDAu5h7k3w2qIrbZfojAFhOHip_TbYHN4sI_EE7xO97IXv3Ya7bbKUZnuI_W1qWrQHw3pGH8TNyRTDaqS-xk7ko-S7iNm4HLTrt9562gbMItB_yHC2_7w7jOqd8ZRxPhpehEb6sWbQxyOFzOreClmC1JB_9mYlFmb1QsgqhY-VIKvdpUca98h_0zsEcyaVqGYalpbqb6Un7vAQ6w";

// Unlock Professional Edition APIs
Realm.Sync.setFeatureToken(token);

function generateRandomTickerSymbol(len) {
    charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    let randomString = '';
    for (let i = 0; i < len; i++) {
        let randomPoz = Math.floor(Math.random() * charSet.length);
        randomString += charSet.substring(randomPoz, randomPoz + 1);
    }
    return randomString;
}

const schema_ = Object.freeze({
    name: '__Class',
    primaryKey: 'name',
    properties: {
        name: 'string',
        permissions: '__Permission[]'
    }
});


const TickerSchema1 = {
    name: 'Ticker1',
    primaryKey: 'tickerSymbol',
    properties: {
        tickerSymbol: {type: 'string', optional: false},
        price: {type: 'int', optional: false},
        companyName: {type: 'string', optional: false},
    }
};

function getStarted() {
    Realm.Sync.User.login(`https://${SERVER}`, USERNAME, PASSWORD)
        .then(user => {
         
            Realm.open({
                sync: {
                    url: `realms://${SERVER}/global/225`,
                    user: user,
                    fullSynchronization: false
                },
                schema: [TickerSchema, TickerSchema1, Realm.Permissions.Permission, Realm.Permissions.User, Realm.Permissions.Role, schema_],
            })
                .then(realm => {
                    let tickerResults = realm.objects(TickerSchema.name);
                    // Add some data to the tickers Realms
                    if (tickerResults.length < totalTickers) {
                        realm.write(() => {
                            for (let index = 0; index < totalTickers; index++) {

                                let x = realm.create('Ticker1', {
                                    tickerSymbol: generateRandomTickerSymbol(3),
                                    price: index,
                                    companyName: faker.company.companyName()
                                }, true);

                                let y = realm.create('Ticker', {
                                    tickerSymbol: generateRandomTickerSymbol(3),
                                    price: index,
                                    companyName: faker.company.companyName(),
                                    ch: x
                                }, true);
                            }

                    
                        });
                    }               
                })
        })
}

getStarted();

“Client”:

const faker = require('faker');
const Realm = require('realm');
const fs = require('fs');

const totalTickers = 100;
const USERNAME = "test";
const PASSWORD = "test";
const SERVER = "some server url";

const TickerSchema = {
    name: 'Ticker',
    primaryKey: 'tickerSymbol',
    properties: {
        tickerSymbol: {type: 'string', optional: false},
        price: {type: 'int', optional: false},
        companyName: {type: 'string', optional: false},
        ch: {type: 'Ticker1', default: null}
    }
};


const TickerSchema1 = {
    name: 'Ticker1',
    primaryKey: 'tickerSymbol',
    properties: {
        tickerSymbol: {type: 'string', optional: false},
        price: {type: 'int', optional: false},
        companyName: {type: 'string', optional: false},
    }
};

const schema_ = Object.freeze({
    name: '__Class',
    primaryKey: 'name',
    properties: {
        name: 'string',
        permissions: '__Permission[]'
    }
});



function generateRandomTickerSymbol(len) {
    charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    let randomString = '';
    for (let i = 0; i < len; i++) {
        let randomPoz = Math.floor(Math.random() * charSet.length);
        randomString += charSet.substring(randomPoz, randomPoz + 1);
    }
    return randomString;
}

function getStarted() {
    Realm.Sync.User.login(`https://${SERVER}`, 'test', 'test')
        .then(user => {
             
            Realm.open({
                sync: {
                    url: `realms://${SERVER}/global/225`,
                    user: user,
                    fullSynchronization: false
                },
                schema: [TickerSchema,  TickerSchema1, Realm.Permissions.Permission, Realm.Permissions.User, Realm.Permissions.Role, schema_
                ],
            })
                .then(realm => {
                 

                    let objects = realm.objects(TickerSchema.name);
                    console.log(objects);
                    let objects2 = realm.objects(TickerSchema1.name);
                    console.log(objects2);
                    objects.addListener((objects, changes) => {
                        changes.modifications.forEach((index) => {
                            const ticker = objects[index];
                            console.log(`Ticker ${ticker.companyName} - ${ticker.tickerSymbol} - ${ticker.price}`)
                        });
                    });

           
                    objects.addListener((objects, changes) => {
                        changes.modifications.forEach((index) => {
                            const ticker = objects[index];
                            console.log(`Ticker ${ticker.companyName} - ${ticker.tickerSymbol} - ${ticker.price}`)
                        });
                    })
                })
        })
}

getStarted();

#2

You need to subscribe to the results:

let objects = realm.objects(TickerSchema.name);
let subscription = objects.subscribe()
let objects2 = realm.objects(TickerSchema1.name);
let subscription2 = objects2.subscribe()

Note: If you have a large data set the subscribe can take longer and cause unexpected results. You can attach a listener to the the subscription object returned and then continue. This method from the tests can be useful (tests/js/permission-tests.js).

function subscribe(results) {
    const subscription = results.subscribe();
    return new Promise((resolve, reject) => {
        subscription.addListener((subscription, state) => {
            if (state === Realm.Sync.SubscriptionState.Complete) {
                resolve();
            }
            else if (state === Realm.Sync.SubscriptionState.Error) {
                reject();
            }
        });
        setTimeout(() => reject("listener never called"), 5000);
    });
}

You can then just do this:

let objects = realm.objects(TickerSchema.name);
subscribe(objects).then(/** use the objects **/)

#3

Thx, works.

Another question, about permissions.

I created two roles (role_c1, role_c2) and mark with them classes Ticker and Ticker1. (User “test” is a member of two of these roles)
role_c2 has no any permissions - when I query only Ticker1 - I got nothing, that is fine.
but when I query Ticker and Ticker1 - I got both objects.

Ticker has a link to Ticker1, so does it mean that ACL does not work correctly?
I expect that if a user has no access to some class he will not get any copies/links/references that related to that class.


#4

The permissions only apply to the primary object, any linked object will be also be available regardless if they are available or not. I’m personally not too keen on this, but it is how it works.

e.g.

let objs = realm.objects('Ticker')
// do subscribing
console.log(objs[0].ch) // will be Ticker1

let objs = realm.objects('Ticker1')
// do subscribing
console.log(objs) // will be null

Interestingly, if you have write permissions in the role, although you can read it via the link you can’t update the linked object.

e.g. the following wont work

let objs = realm.objects('Ticker')
// do subscribing
realm.write(() => {
  objs[0].ch.price = 0
})

#5

Thx, ok. It is not very good, but I know how I could achieve that I want:

I have public content - a list of books (just names and descriptions), and content that will be available after purchase.
My idea is next: to class “book” will have access only users with “customer”-role (this role will have access to the class “book”), so when a user buys something, we will add him to the group “customer”.

A question: a user makes a query to get a book with id=x (after purchase), realm “downloads” content. and now the user has data in his local database. Then the user closes/restarts the application, should we make some query for the book with id=x to get updates for the book? Or realm will sync everything that it already has locally?