User Search Event Handler
Author: Ian Ward
Language: JavaScript
Date: September 1, 2017
This sample app demonstrates how to stream a subset of data from a public Realm file to a single user’s private Realm.
This is useful in scenarios where the public Realm is very large, and the user is only interested in isolating certain records from it.
It wouldn’t make sense to download the entire public Realm to the device, so this mechanism mitigates this by copying the records that the user specifies.
How to try it out:
- Create text files named
admin_token.base64
andaccess-token.enterprise
, containing your ROS instance’s admin key, and your Enterprise/Professional token respectively into the toEventListener
folder. - Copy the Professional edition NPM package to the folder and update the filename in
package.json
if needed (Currently set asrealm-1.4.3-professional.tgz
). - Run
npm install
to get the needed modules. - Start the event handler by running
node usersearch.js
.
You can run the included UserSearch app to test it out. You will need to update the credentials in the file ViewController.swift
to match a user existing on the server.
Using an _admin
Realm
This code is similar but shows how to search the __admin realm which contains all of the User’s emails for instance. Editing the __admin realm could cause your ROS to have a critical failure but opening the __admin realm and just reading from it is fine.
How to try it out:
- Copy
admin_token.base64
andaccess-token.enterprise
to folder - Copy the PE node.js binding package to the folder and update the filename in
package.json
if needed. - Run
npm install
to get the needed modules. - Start the event handler by running
node usersearch.js
.
You can run the included UserSearch app to test it out. You will need to update the credentials in the file ViewController.swift
to match a user existing on the server.
const Realm = require('realm');
const fs = require('fs');
const server_url = 'realm://localhost:9080';
const REALM_ADMIN_TOKEN = fs.readFileSync('./admin_token.base64', 'utf-8');
const ENTERPRISE_TOKEN = fs.readFileSync('./access-token.enterprise', 'utf-8');
Realm.Sync.setFeatureToken(ENTERPRISE_TOKEN); // needed to enable global listener functionality
Realm.Sync.setLogLevel('error');
const adminUser = Realm.Sync.User.adminUser(REALM_ADMIN_TOKEN);
// -------------------
function onAdmin(changeEvent) {
console.log("admin available");
const adminRealm = changeEvent.realm;
function handleChange(changeEvent) {
console.log(changeEvent.path);
const changes = changeEvent.changes["UserSearch"];
// no reason to do any work if there are no requests
if (typeof changes === "undefined")
return;
if (changes.insertions.length == 0 && changes.modifications.length == 0)
return;
const searchRealm = changeEvent.realm; // workaround for GN returning new instance on every access
const requests = searchRealm.objects("UserSearch");
const accounts = adminRealm.objects('Account');
// Find users matching the request
searchRealm.write(() => {
// handle new requests
changes.insertions.forEach((index) => {
const obj = requests[index];
if (obj.pattern != "") {
const matches = accounts.filtered("provider_id CONTAINS[c] $0", obj.pattern);
matches.forEach((match) => {
obj.users.push({userid: match.user.id, email: match.provider_id});
});
}
obj.resultPattern = obj.pattern;
});
// live update result if request is modified
changes.modifications.forEach((index) => {
const obj = requests[index];
if (obj.pattern == "") {
searchRealm.delete(obj.users);
}
else {
const matches = accounts.filtered("provider_id CONTAINS[c] $0", obj.pattern);
// remove users that are no longer matching
const toDelete = [];
obj.users.forEach((profile) => {
if (matches.filtered("user.id == $0", profile.userid).length == 0) {
toDelete.push(profile);
}
});
searchRealm.delete(toDelete);
// add new matches
matches.forEach((match) => {
if (obj.users.filtered("userid == $0", match.user.id).length == 0) {
obj.users.push({userid: match.user.id, email: match.provider_id});
}
});
}
obj.resultPattern = obj.pattern;
});
});
}
Realm.Sync.addListener(server_url, adminUser, "^/.*?/usersearch$", 'change', handleChange);
// now that we have the admin realm, we don't need the listener anymore
Realm.Sync.removeListener("^/__admin$", 'change', onAdmin)
}
Realm.Sync.addListener(server_url, adminUser, "^/__admin$", 'change', onAdmin);
console.log('listening');