Docs Menu
Docs Home
/ /
Atlas Device SDKs
/

Quick Start - Node.js SDK

On this page

  • Import Realm
  • Define Your Object Model
  • Open a Realm
  • Find, Sort, and Filter Objects
  • Create, Modify, and Delete Realm Objects
  • Watch a Collection
  • Close a Realm
  • Add Device Sync (Optional)
  • Prerequisites
  • Initialize the App
  • Authenticate a User
  • Define an Object Model
  • Open a Synced Realm

This page contains information to quickly get Realm integrated into your app.

If you haven't already, install the Realm Node.js SDK.

At the top of your source files where you want to use Realm, add the following line to import the SDK and the BSON library.

import Realm, { BSON } from "realm";

Your application's object model defines the data that you can store within Realm.

To define a Realm object type, create a schema object that specifies the type's name and properties. The type name must be unique among object types in a realm. For details on how to define specific properties, see Define Object Properties.

The following code shows how to define an object model for a Task object. In this example:

  • The primaryKey is the _id of type int. Another common type used for primary keys is ObjectId.

  • The name field is required.

  • The status and owner_id fields are optional, denoted by the question mark immediately after the data type.

export class QuickstartTask extends Realm.Object {
static schema = {
name: "Task",
properties: {
_id: "objectId",
name: "string",
status: "string?",
owner_id: "string?",
},
primaryKey: "_id",
};
}
export class QuickstartTask extends Realm.Object<Task> {
_id!: BSON.ObjectID;
name!: string;
status?: string;
owner_id?: string;
static schema: ObjectSchema = {
name: "Task",
properties: {
_id: "objectId",
name: "string",
status: "string?",
owner_id: "string?",
},
primaryKey: "_id",
};
}

To open a realm, pass a Realm.BaseConfiguration object to Realm.open().

const realm = await Realm.open({
schema: [QuickstartTask],
});

The following code demonstrates how to:

  • Query for all instances of the "Task" object type.

  • Filter the query to retrieve only the tasks that are "Open".

  • Sort the tasks by the name in an ascending order.

// Query for specific obect using primary key.
const specificTask = realm.objectForPrimaryKey(QuickstartTask, testId);
// Query realm for all instances of the "Task" type.
const tasks = realm.objects(QuickstartTask);
// Filter for all tasks with a status of "Open".
const openTasks = tasks.filtered("status = 'Open'");
// Sort tasks by name in ascending order.
const tasksByName = tasks.sorted("name");

Once you have opened a realm, you can create, modify, and delete objects in it. All write operations must occur within a write transaction.

const allTasks = realm.objects(QuickstartTask);
// Add a couple of Tasks in a single, atomic transaction.
realm.write(() => {
realm.create(QuickstartTask, {
_id: firstId,
name: "go grocery shopping",
status: "Open",
});
realm.create(QuickstartTask, {
_id: secondId,
name: "go exercise",
status: "Open",
});
});
const task1 = allTasks.find(
(task) => task._id.toString() == firstId.toString()
);
const task2 = allTasks.find(
(task) => task._id.toString() == secondId.toString()
);
realm.write(() => {
// Modify an object.
task1!.status = "InProgress";
// Delete an object.
realm.delete(task2!);
});

You can watch a realm, collection, or object for changes by registering event handlers with the Realm.addListener() Object.addListener() Collection.addListener() methods.

Important

Order Matters

In collection notification handlers, always apply changes in the following order: deletions, insertions, then modifications. Handling insertions before deletions may result in unexpected behavior.

In the following example, an application developer watches for changes to the Task collection.

// Define the collection notification listener.
const listener = (tasks, changes) => {
// Update UI in response to deleted objects.
changes.deletions.forEach((index) => {
// Deleted objects cannot be accessed directly,
// but we can update a UI list, etc. knowing the index.
console.log(`A task was deleted at the ${index} index.`);
// ...
});
// Update UI in response to inserted objects.
changes.insertions.forEach((index) => {
const insertedTasks = tasks[index];
console.log(`insertedTasks: ${JSON.stringify(insertedTasks, null, 2)}`);
// ...
});
// Update UI in response to modified objects.
// `newModifications` contains an index to the modified object's position
// in the collection after all deletions and insertions have been applied.
changes.newModifications.forEach((index) => {
const modifiedTask = tasks[index];
console.log(`modifiedTask: ${JSON.stringify(modifiedTask, null, 2)}`);
// ...
});
};
// Observe collection notifications.
tasks.addListener(listener);
// Define the collection notification listener.
//@ts-expect-error TYPEBUG: OrderedCollection is incorrectly implemented
const listener: Realm.CollectionChangeCallback = (
tasks: Realm.OrderedCollection<QuickstartTask>,
changes: Realm.CollectionChangeSet
) => {
// Update UI in response to deleted objects.
changes.deletions.forEach((index) => {
// Deleted objects cannot be accessed directly,
// but we can update a UI list, etc. knowing the index.
console.log(`A task was deleted at the ${index} index.`);
// ...
});
// Update UI in response to inserted objects.
changes.insertions.forEach((index) => {
const insertedTasks = tasks[index];
console.log(`insertedTasks: ${JSON.stringify(insertedTasks, null, 2)}`);
// ...
});
// Update UI in response to modified objects.
// `newModifications` contains an index to the modified object's position
// in the collection after all deletions and insertions have been applied.
changes.newModifications.forEach((index) => {
const modifiedTask = tasks[index];
console.log(`modifiedTask: ${JSON.stringify(modifiedTask, null, 2)}`);
// ...
});
};
// Observe collection notifications.
//@ts-expect-error TYPEBUG: OrderedCollection is incorrectly implemented
tasks.addListener(listener);

Call the realm.close() method when done with a realm instance to avoid memory leaks.

// Close the realm.
realm.close();

This section illustrates how to authenticate with an Anonymous User and open a Flexible Sync realm to sync data between devices.

To use App Services features, such as authentication and sync, you must first access your App Services App using your App ID. You can find your App ID in the App Services UI.

// Initialize your App.
const app = new Realm.App({
id: "<yourAppId>",
});

To authenticate and log in a user, call App.logIn(). When anonymous authentication is enabled, users can immediately log into your app without providing any identifying information:

// Initialize your App.
const app = new Realm.App({
id: "<yourAppId>",
});
// Authenticate an anonymous user.
const anonymousUser = await app.logIn(Realm.Credentials.anonymous());

Object models for synced realms work the same way as local-only Realms. Define your object model just as you would for a local-only Realm.

export class QuickstartTask extends Realm.Object {
static schema = {
name: "Task",
properties: {
_id: "objectId",
name: "string",
status: "string?",
owner_id: "string?",
},
primaryKey: "_id",
};
}
export class QuickstartTask extends Realm.Object<Task> {
_id!: BSON.ObjectID;
name!: string;
status?: string;
owner_id?: string;
static schema: ObjectSchema = {
name: "Task",
properties: {
_id: "objectId",
name: "string",
status: "string?",
owner_id: "string?",
},
primaryKey: "_id",
};
}

After you have initialized your App, authenticated a user, and defined your object model, you can create a SyncConfiguration.

To open a Flexible Sync realm, call Realm.open(). Pass in a BaseConfiguration object, which must include the sync property defining a SyncConfiguration object. To use Flexible Sync, in the SyncConfiguration, you must include include a user and flexible: true.

Additionally, you need at least one subscription before you can read from or write to the realm. Use Configuration.sync.initialSubscriptions to define the initial subscription set when the Realm file is first opened.

// Initialize your App.
const app = new Realm.App({
id: "<yourAppId>",
});
// Authenticate an anonymous user.
const anonymousUser = await app.logIn(Realm.Credentials.anonymous());
// Create a `SyncConfiguration` object.
const config = {
schema: [QuickstartTask],
sync: {
// Use the previously-authenticated anonymous user.
user: anonymousUser,
// Set flexible sync to true to enable sync.
flexible: true,
// Define initial subscriptions to start syncing data as soon as the
// realm is opened.
initialSubscriptions: {
update: (subs, realm) => {
subs.add(
// Get objects that match your object model, then filter them by
// the `owner_id` queryable field
realm
.objects(QuickstartTask)
.filtered(`owner_id == "${anonymousUser.id}"`)
);
},
},
},
};
const realm = await Realm.open(config);
// Initialize your App.
const app = new Realm.App({
id: "<yourAppId>",
});
// Authenticate an anonymous user.
const anonymousUser = await app.logIn(Realm.Credentials.anonymous());
// Create a `SyncConfiguration` object.
const config: Realm.Configuration = {
schema: [QuickstartTask],
sync: {
// Use the previously-authenticated anonymous user.
user: anonymousUser,
// Set flexible sync to true to enable sync.
flexible: true,
// Define initial subscriptions to start syncing data as soon as the
// realm is opened.
initialSubscriptions: {
update: (subs, realm) => {
subs.add(
// Get objects that match your object model, then filter them by
// the `owner_id` queryable field
realm
.objects(QuickstartTask)
.filtered(`owner_id == "${anonymousUser.id}"`)
);
},
},
},
};
const realm = await Realm.open(config);

The syntax to read, write, and watch for changes on a synced realm is identical to the syntax for non-synced realms above. While you work with local data, a background thread efficiently integrates, uploads, and downloads changesets.

Back

Install

Next

Realm Files