Designing schemas for NoSQL databases like Cosmos DB requires shifting away from relational normalization. Instead of dividing entities across table joins, developers must choose between embedding nested objects or creating separate referenced documents.
When to Embed Child Documents
Embedding stores related items within the same JSON document. Use this approach when:
- There is a contained, 1-to-few relationship between entities (e.g., customer address list).
- Data is queried and updated together frequently.
- The total size of the combined JSON document stays well under the 2 MB Cosmos DB limit.
When to Reference Separate Documents
Referencing uses distinct documents linked by primary keys. Choose referencing when:
- Entities have 1-to-many or many-to-many relationships without upper boundaries (e.g., user post comments).
- Data items are updated independently and frequently, avoiding high RU write charges on huge documents.
- Read patterns require fetching parent documents without overhead from large child collections.
By balancing read efficiency and write payload size, you optimize both query performance and billing costs.
In Azure Cosmos DB, embed data when it is usually read and updated with its parent. Store a separate document when it has its own lifecycle, grows without a clear bound, or is accessed independently. The best choice depends less on whether the data looks “relational” and more on how your application uses it.
Embed data that belongs to a single read
For example, an order document can contain its order line items. An order-details screen can then retrieve the order and its lines with one point read, without issuing extra queries for each item.
Embedding is a good fit when the child data is bounded, commonly fetched with the parent, and usually changed as part of the same operation. It can also make updates simpler when the data stays within the same logical partition.
Reference data with an independent lifecycle
A customer record is often better stored separately from each order. Orders can refer to a customer ID, while the customer profile remains independently editable and reusable. This avoids copying a growing customer record into every order.
References in Cosmos DB are application-managed: they do not provide automatic relational joins. If a screen needs both documents, your application typically reads them separately or keeps selected fields denormalized in the order when that suits the access pattern.
Check growth and transaction boundaries
A large or continually growing unbounded child collection is usually a poor candidate for embedding. Each update to a document also writes that document, so frequently changing a large embedded structure can add cost and contention. Cosmos DB items have a size limit, so a document that keeps expanding needs special attention.
Also consider the logical partition boundary: transactional operations are limited to items in the same logical partition. If related documents must change atomically, their partitioning needs to support that requirement.
A practical rule: embed small, bounded data that you read and update together; reference data that is independently queried, shared, or likely to grow. Model around the operations your application actually performs, then validate the choice against query patterns, partitioning, and request cost.