Docs Menu

Partitions

On this page

  • Overview
  • Key Terms
  • Partition Key
  • Partition Value
  • Partition Strategy
  • Firehose Strategy
  • User Strategy
  • Team Strategy
  • Channel Strategy
  • Region Strategy
  • Bucket Strategy

Partitions are the abstraction between the Realm object model and the MongoDB document model. Each model operates under different constraints and assumptions.

A MongoDB Atlas cluster consists of several remote servers. These servers provide the storage for your synced data. The Atlas cluster stores documents in collections. Each MongoDB collection maps to a different Realm object type. Each document in a collection represents a specific Realm object.

A synced realm is a local file on a device. A synced realm may contain some or all the objects relevant to the end user. A client app may use more than one synced realm to access all the objects that the application needs.

Partitions link objects in Realm Database to documents in MongoDB. When you initialize a synced realm file, one of its parameters is a partition value. Your client app creates objects in the synced realm. When those objects sync, the partition value becomes a field in the MongoDB documents. The value of this field determines which MongoDB documents the client can access.

At a high level:

  • A partition maps to a subset of the documents in a synced cluster.
  • All documents in a partition have the same read/write permissions for a given user.
  • Realm maps each partition to an individual synced .realm file.
  • Each object in a synced realm has a corresponding document in the partition.
A diagram that explains partitioning using groups of shapes and colors. MongoDB collections group by shape (equivalent to object types) while realms group by color (equivalent to partition value).

Partition shape data in an MongoDB Atlas cluster. Each shape represents an object type. Partitions are determined by each shape's color: red, green, or blue.

A partition key is a named field that you specify when you configure Realm Sync. Realm Sync uses this key to determine which partition contains a given document.

Depending on your data model and the complexity of your app, your partition key could be either:

  • A property that already exists in each document and that logically partitions data. For example, consider an app where every document is private to a specific user. You might store the user's ID value in an owner_id field and then use that as the partition key.
  • A synthetic property that you create to partition data (e.g. _partition). You might use this when your app does not include a natural partition key.

You can make the partition key required or optional on your objects. Realm maps any object that does not include a partition key to a default partition - null partition.

Consider the following when choosing a partition key:

  • Partition keys must be one of these types: String, ObjectID, Long, or UUID.
  • Realm clients should never modify the partition value directly. You cannot use any field that clients can modify as a partition key.
  • Partition keys use the same field name in every synced document. The partition key should not collide with any field name in any object's model.
Example

The following schemas demonstrate natural and synthetic partition keys:

  • The owner_id field is a natural key because it's already part of the app's data model.
  • The _partition field is a synthetic key because its only purpose is to serve as a partition key.

An app can only specify a single partition key, but either of these fields could work depending on your use case:

{
"title": "note",
"bsonType": "object",
"required": [
"_id",
"_partition",
"owner_id",
"text"
],
"properties": {
"_id": { "bsonType": "objectId" },
"_partition": { "bsonType": "string" },
"owner_id": { "bsonType": "string" },
"text": { "bsonType": "string" }
}
}
{
"title": "notebook",
"bsonType": "object",
"required": [
"_id",
"_partition",
"owner_id",
"notes"
],
"properties": {
"_id": { "bsonType": "objectId" },
"_partition": { "bsonType": "string" },
"owner_id": { "bsonType": "string" },
"notes": {
"bsonType": "array",
"items": { "bsonType": "objectId" }
}
}
}

Your app's partition key is a central part of a Sync-enabled app's data model. When you set a partition key in your Sync configuration, you cannot later reassign the key's field. If you need to change a partition key, you must terminate sync. Then, you can enable it again with the new partition key. However, this requires all client applications to reset and sync data into new realms.

Warning
Restore Sync after Terminating Sync

When you terminate and re-enable Realm Sync, clients can no longer Sync. Your client must implement a client reset handler to restore Sync. This handler can discard or attempt to recover unsynchronized changes.

A partition value is a value of the partition key field for a given document. Documents with the same partition value belong to the same partition. They sync to the same realm file, and share user-level data access permissions.

A partition's value is the identifier for its corresponding synced realm. You specify the partition's value when you open it as a synced realm in the client. If you change a partition value in Atlas, Realm interprets the change as two operations:

  • A delete from the old partition.
  • An insert into the new partition.
Warning

If you change a document's partition value, you lose client-side unsynced changes to the object.

A partition strategy is a key/value pattern to divide objects into partitions. Different use cases call for different partition strategies. You can compose partition strategies within the same app to form a larger strategy. This enables you to handle arbitrarily complex use cases.

Which strategy to use depends on your app's data model and access patterns. Consider an app with both public and private data. You might put some data, like announcements, in a public partition. You might restrict other data, like personal information, to privileged users.

When developing a partition strategy, consider:

  • Data Security: Users may need different read and write access permissions to subsets of data. Consider the permissions users need for types of documents. A user has the same permissions for every document in a partition.
  • Storage Capacity: Your client apps may have limited on-device storage on some devices and platforms. A partition strategy should take storage limitations into account. Make sure a user can store their synced data on their device.
Tip
Combine Strategies

You can use a partition key name like _partition with a query string as the value. This lets you use multiple strategies in the same app. For example:

_partitionKey: "user_id=abcdefg"
_partitionKey: "team_id=1234&city='New York, NY'"

You can use functions and rule expressions to parse the string. Sync can determine whether a user has access to a partition based on the combined strategy.

A firehose partition strategy groups all documents into a single partition. With this structure, every user syncs all of your app's data to their device. This approach is functionally a decision to not partition data. This works for basic applications or small public data sets.

  • Data Security. All data is public to clients with a realm that uses the partition. If a user has read or write access to the partition, they can read or write any document.
  • Storage Capacity. Every user syncs every document in the partition. All data must fit within your most restrictive storage limitation. Use this strategy only when data sets are small and do not grow quickly.

One way to create a firehose is to set the partition key as an optional field. Don't include a value for this field in any document. Realm maps any document that doesn't include a partition value to the null partition.

You can also set a static partition value. This is when the partition value doesn't change based on the user or data. For example, realms across all clients could use the partition value "MyPartitionValue".

Example

An app lets users browse scores and statistics for local high school baseball games. Consider the following documents in the games and teams collections:

collection games: [
{ teams: ["Brook Ridge Miners", "Southside Rockets"], score: { ... }, date: ... }
{ teams: ["Brook Ridge Miners", "Uptown Bombers"], score: { ... }, date: ... }
{ teams: ["Brook Ridge Miners", "Southside Rockets"], score: { ... }, date: ... }
{ teams: ["Southside Rockets", "Uptown Bombers"], score: { ... }, date: ... }
{ teams: ["Brook Ridge Miners", "Uptown Bombers"], score: { ... }, date: ... }
{ teams: ["Southside Rockets", "Uptown Bombers"], score: { ... }, date: ... }
]
collection teams: [
{ name: "Brook Ridge Miners" }
{ name: "Southside Rockets" }
{ name: "Uptown Bombers" }
]

The total number of games is small. A small number of local teams only play a few games each year. Most devices should be able to download all game data for easy offline access. In this case, the firehose strategy is appropriate. The data is public and documents don't need a partition key.

The strategy maps the collections to the following realms:

realm null: [
Game { teams: ["Brook Ridge Miners", "Southside Rockets"], score: { ... }, date: ... }
Game { teams: ["Brook Ridge Miners", "Uptown Bombers"], score: { ... }, date: ... }
Game { teams: ["Brook Ridge Miners", "Southside Rockets"], score: { ... }, date: ... }
Game { teams: ["Southside Rockets", "Uptown Bombers"], score: { ... }, date: ... }
Game { teams: ["Brook Ridge Miners", "Uptown Bombers"], score: { ... }, date: ... }
Game { teams: ["Southside Rockets", "Uptown Bombers"], score: { ... }, date: ... }
Team { name: "Brook Ridge Miners" }
Team { name: "Southside Rockets" }
Team { name: "Uptown Bombers" }
]

A user partition strategy groups private documents for each user. These documents go into a partition specific to that user. This works when each document has an owner, and nobody else needs the data. A username or ID that identifies the owner makes a natural partition key.

  • Data Security. Data in a user partition is specific to a given user. It may contain information private to that user. Each user syncs only their own partition. Other users cannot access documents in the partition.
  • Storage Capacity. Each user only syncs data from their own partition. Their data must fit within their device's storage constraints. Use this strategy only when each user has a manageable amount of data.
Example

A music streaming app stores data about playlists and song ratings for each user. Consider the following documents in the playlists and ratings collections:

collection playlists: [
{ name: "Work", owner_id: "dog_enthusiast_95", song_ids: [ ... ] }
{ name: "Party", owner_id: "cat_enthusiast_92", song_ids: [ ... ] }
{ name: "Soup Tunes", owner_id: "dog_enthusiast_95", song_ids: [ ... ] }
{ name: "Disco Anthems", owner_id: "PUBLIC", song_ids: [ ... ] }
{ name: "Deep Focus", owner_id: "PUBLIC", song_ids: [ ... ] }
]
collection ratings: [
{ owner_id: "dog_enthusiast_95", song_id: 3, rating: -1 }
{ owner_id: "cat_enthusiast_92", song_id: 1, rating: 1 }
{ owner_id: "dog_enthusiast_95", song_id: 1, rating: 1 }
]

Every document includes the owner_id field. This is a good partition key for a user partition strategy. It naturally maps documents to individual users. This limits the data on each device to playlists and ratings for the device's user.

  • Users have read and write access to their user realm. This contains playlists they have created and ratings that they've given to songs.
  • Every user has read access to the realm for partition value PUBLIC. This contains playlists that are available to all users.

The strategy maps the collections to the following realms:

realm dog_enthusiast_95: [
Playlist { name: "Work", owner_id: "dog_enthusiast_95", song_ids: [ ... ] }
Playlist { name: "Soup Tunes", owner_id: "dog_enthusiast_95", song_ids: [ ... ] }
Rating { owner_id: "dog_enthusiast_95", song_id: 3, rating: -1 }
Rating { owner_id: "dog_enthusiast_95", song_id: 1, rating: 1 }
]
realm cat_enthusiast_92: [
Playlist { name: "Party", owner_id: "cat_enthusiast_92", song_ids: [ ... ] }
Rating { owner_id: "cat_enthusiast_92", song_id: 1, rating: 1 }
]
realm PUBLIC: [
Playlist { name: "Disco Anthems", owner_id: "PUBLIC", song_ids: [ ... ] }
Playlist { name: "Deep Focus", owner_id: "PUBLIC", song_ids: [ ... ] }
]

A team partition strategy groups private documents shared by a team of users. A team might include a store location's employees or a band's members. Each team has a partition specific to that group. All users in the team share access and ownership of the team's documents.

  • Data Security. Data in a team partition is specific to a given team. It may contain data private to the team but not to a member of the team. Each user syncs partitions for the teams they belong to. Users not in a team cannot access documents in the team's partition.
  • Storage Capacity: Each user only syncs data from their own teams. The data from a user's teams must fit within their device's storage constraints. Use this strategy when users belong to a manageable number of teams. If users belong to many teams, the combined realms could contain a lot of data. You may need to limit the number of team partitions synced at a time.
Example

An app lets users create projects to collaborate with other users. Consider the following documents in the projects and tasks collections:

collection projects: [
{ name: "CLI", owner_id: "cli-team", task_ids: [ ... ] }
{ name: "API", owner_id: "api-team", task_ids: [ ... ] }
]
collection tasks: [
{ status: "complete", owner_id: "api-team", text: "Import dependencies" }
{ status: "inProgress", owner_id: "api-team", text: "Create app MVP" }
{ status: "inProgress", owner_id: "api-team", text: "Investigate off-by-one issue" }
{ status: "todo", owner_id: "api-team", text: "Write tests" }
{ status: "inProgress", owner_id: "cli-team", text: "Create command specifications" }
{ status: "todo", owner_id: "cli-team", text: "Choose a CLI framework" }
]

Every document includes the owner_id field. This is a good partition key for a team partition strategy. It naturally maps documents to individual teams. This limits the data on each device. Users only have projects and tasks that are relevant to them.

  • Users have read and write access to partitions owned by teams where they're a member.
  • Data stored in a teams or users collection can map users to team membership:

    collection teams: [
    { name: "cli-team", member_ids: [ ... ] }
    { name: "api-team", member_ids: [ ... ] }
    ]
    collection users: [
    { name: "Joe", team_ids: [ ... ] }
    { name: "Liz", team_ids: [ ... ] }
    { name: "Matt", team_ids: [ ... ] }
    { name: "Emmy", team_ids: [ ... ] }
    { name: "Scott", team_ids: [ ... ] }
    ]

The strategy maps the collections to the following realms:

realm cli-team: [
Project { name: "CLI", owner_id: "cli-team", task_ids: [ ... ] }
Task { status: "inProgress", owner_id: "cli-team", text: "Create command specifications" }
Task { status: "todo", owner_id: "cli-team", text: "Choose a CLI framework" }
]
realm api-team: [
Project { name: "API", owner_id: "api-team", task_ids: [ ... ] }
Task { status: "complete", owner_id: "api-team", text: "Import dependencies" }
Task { status: "inProgress", owner_id: "api-team", text: "Create app MVP" }
Task { status: "inProgress", owner_id: "api-team", text: "Investigate off-by-one issue" }
Task { status: "todo", owner_id: "api-team", text: "Write tests" }
]

A channel partition strategy groups documents for a common topic or domain. Each topic or domain has its own partition. Users can choose to access or subscribe to specific channels. A name or ID may identify these channels in a public list.

  • Data Security. Data in a channel partition is specific to a topic or area. Users can choose to access these channels. You can limit a user's access to a subset of channels. You could prevent users from accessing channels entirely. When user has read or write permission for a channel, they can access any document in the partition.
  • Storage Capacity. Users can choose to sync data from any allowed channel. All data from a user's channels must fit within their device's storage constraints. Use this strategy to partition public or semi-private data sets. This strategy breaks up data sets that would not fit within storage constraints.
Example

An app lets users create chatrooms based on topics. Users can search for and join channels for any topic that interests them. Consider these documents in the chatrooms and messages collections:

collection chatrooms: [
{ topic: "cats", description: "A place to talk about cats" }
{ topic: "sports", description: "We like sports and we don't care who knows" }
]
collection messages: [
{ topic: "cats", text: "Check out this cute pic of my cat!", timestamp: 1625772933383 }
{ topic: "cats", text: "Can anybody recommend a good cat food brand?", timestamp: 1625772953383 }
{ topic: "sports", text: "Did you catch the game last night?", timestamp: 1625772965383 }
{ topic: "sports", text: "Yeah what a comeback! Incredible!", timestamp: 1625772970383 }
{ topic: "sports", text: "I can't believe how they scored that goal.", timestamp: 1625773000383 }
]

Every document includes the topic field. This is a good partition key for a channel partition strategy. It naturally maps documents to individual channels. This reduces the data on each device. Data only contains messages and metadata for channels the user has chosen.

  • Users have read and write access to chatrooms where they're subscribed. Users can change or delete any message - even those sent by other users. To limit write permissions, you could give users read-only access. Then, handle sending messages with a serverless function.
  • Store the use's subscribed channels in either the chatrooms or users collection:

    collection chatrooms: [
    { topic: "cats", subscriber_ids: [ ... ] }
    { topic: "sports", subscriber_ids: [ ... ] }
    ]
    collection users: [
    { name: "Joe", chatroom_ids: [ ... ] }
    { name: "Liz", chatroom_ids: [ ... ] }
    { name: "Matt", chatroom_ids: [ ... ] }
    { name: "Emmy", chatroom_ids: [ ... ] }
    { name: "Scott", chatroom_ids: [ ... ] }
    ]

The strategy maps the collections to the following realms:

realm cats: [
Chatroom { topic: "cats", description: "A place to talk about cats" }
Message { topic: "cats", text: "Check out this cute pic of my cat!", timestamp: 1625772933383 }
Message { topic: "cats", text: "Can anybody recommend a good cat food brand?", timestamp: 1625772953383 }
]
realm sports: [
Chatroom { topic: "sports", description: "We like sports and we don't care who knows" }
Message { topic: "sports", text: "Did you catch the game last night?", timestamp: 1625772965383 }
Message { topic: "sports", text: "Yeah what a comeback! Incredible!", timestamp: 1625772970383 }
Message { topic: "sports", text: "I can't believe how they scored that goal.", timestamp: 1625773000383 }
]

A region partition strategy groups documents related to a location or region. Each partition contains documents specific to those areas.

  • Data Security. Data is specific to a given geographic area. You can limit a user's access to their current region. Alternately, give access to data on a region-by-region basis.
  • Storage Capacity. Storage needs vary depending on size and usage patterns for the region. Users might only sync data in their own region. The data for any region should fit within a device's storage constraints. If users sync multiple regions, partition into smaller subregions. This helps avoid syncing unneeded data.
Example

An app lets users search for nearby restaurants and order from their menus. Consider the following documents in the restaurants collection:

collection restaurants: [
{ city: "New York, NY", name: "Joe's Pizza", menu: [ ... ] }
{ city: "New York, NY", name: "Han Dynasty", menu: [ ... ] }
{ city: "New York, NY", name: "Harlem Taste", menu: [ ... ] }
{ city: "Chicago, IL", name: "Lou Malnati's", menu: [ ... ] }
{ city: "Chicago, IL", name: "Al's Beef", menu: [ ... ] }
{ city: "Chicago, IL", name: "Nando's", menu: [ ... ] }
]

Every document includes the city field. This is a good partition key for a region partition strategy. It naturally maps documents to specific physical areas. This limits data to messages and metadata for a user's current city. Users have read access to restaurants in their current region. You could determine the user's region in your application logic.

The strategy maps the collections to the following realms:

realm New York, NY: [
{ city: "New York, NY", name: "Joe's Pizza", menu: [ ... ] }
{ city: "New York, NY", name: "Han Dynasty", menu: [ ... ] }
{ city: "New York, NY", name: "Harlem Taste", menu: [ ... ] }
]
realm Chicago, IL: [
{ city: "Chicago, IL", name: "Lou Malnati's", menu: [ ... ] }
{ city: "Chicago, IL", name: "Al's Beef", menu: [ ... ] }
{ city: "Chicago, IL", name: "Nando's", menu: [ ... ] }
]

A bucket partition strategy groups documents by range. When documents range along a dimension, a partition contains a subrange. Consider time-based bucket ranges. Triggers move documents to new partitions when they fall out of their bucket range.

  • Data Security. Limit users to read or write only specific buckets. Data may flow between buckets. Consider access permissions for a document across all possible buckets.
  • Storage Capacity. Storage needs vary based on size and usage patterns for each bucket. Consider which buckets users need to access. Limit the size of buckets to fit within a device's storage constraints. If users sync many buckets, partition into smaller buckets. This helps avoid syncing unneeded data.
Example

An IoT app shows real-time views of sensor readings several times a second. Buckets derive from the number of seconds since the reading came in. Consider these documents in the readings collection:

collection readings: [
{ bucket: "0s<t<=60s", timestamp: 1625773000383 , data: { ... } }
{ bucket: "0s<t<=60s", timestamp: 1625772970383 , data: { ... } }
{ bucket: "0s<t<=60s", timestamp: 1625772965383 , data: { ... } }
{ bucket: "60s<t<=300s", timestamp: 1625772953383 , data: { ... } }
{ bucket: "60s<t<=300s", timestamp: 1625772933383 , data: { ... } }
]

Every document includes the bucket field. This field maps documents to specific time ranges. A user's device only contains sensor readings for the window they view.

  • Users have read access to sensor readings for any time bucket.
  • Sensors use client apps with write access to upload readings.

The strategy maps the collections to the following realms:

realm 0s<t<=60s: [
Reading { bucket: "0s<t<=60s", timestamp: 1625773000383 , data: { ... } }
Reading { bucket: "0s<t<=60s", timestamp: 1625772970383 , data: { ... } }
Reading { bucket: "0s<t<=60s", timestamp: 1625772965383 , data: { ... } }
]
realm 60s<t<=300s: [
Reading { bucket: "60s<t<=300s", timestamp: 1625772953383 , data: { ... } }
Reading { bucket: "60s<t<=300s", timestamp: 1625772933383 , data: { ... } }
]
←  Flexible SyncSync Rules and Permissions →
Give Feedback
© 2022 MongoDB, Inc.

About

  • Careers
  • Investor Relations
  • Legal Notices
  • Privacy Notices
  • Security Information
  • Trust Center
© 2022 MongoDB, Inc.