graph LR A[Customer Document] --> B(Orders); B --> C(Order 1); B --> D(Order 2); C --> E(Items); D --> F(Items);
Document stores, like MongoDB and Couchbase, offer flexibility and scalability unmatched by relational databases. However, this flexibility comes with the responsibility of carefully designing your data model to avoid performance bottlenecks and maintain data integrity. Choosing the right design pattern is important for the success of your application. This post explores many key document store design patterns, illustrating their strengths and weaknesses with examples.
The embedded documents pattern is ideal when you have a one-to-many relationship between documents where the child documents are strongly related to the parent and rarely exist independently. Embedding the child documents within the parent document reduces the number of database queries needed to retrieve related data.
Advantages:
Disadvantages:
Example (MongoDB):
{"_id": ObjectId("64e9f07a1c9667a595f3b1e5"),
"customer": {
"name": "John Doe",
"email": "john.doe@example.com"
,
}"orders": [
{"orderId": "12345",
"items": [
"item": "Shirt", "quantity": 2},
{"item": "Pants", "quantity": 1}
{
],
}
{"orderId": "67890",
"items": [
"item": "Shoes", "quantity": 1}
{
]
}
] }
Diagram:
graph LR A[Customer Document] --> B(Orders); B --> C(Order 1); B --> D(Order 2); C --> E(Items); D --> F(Items);
The reference documents pattern uses references (typically object IDs) to link related documents. This is suitable for many-to-many relationships or when child documents are frequently updated or accessed independently.
Advantages:
Disadvantages:
Example (MongoDB):
// Customer Document
{"_id": ObjectId("64e9f07a1c9667a595f3b1e6"),
"name": "Jane Doe",
"orderIds": [ObjectId("64e9f07b1c9667a595f3b1e7"), ObjectId("64e9f07c1c9667a595f3b1e8")]
}
// Order Document
{"_id": ObjectId("64e9f07b1c9667a595f3b1e7"),
"orderId": "11111",
"items": [{"item": "Dress", "quantity": 1}]
}
Diagram:
graph LR A[Customer Document] --> B(Order IDs); B -- References --> C[Order Document];
The polymorphic documents pattern allows you to store documents with varying structures under a single collection. This is useful when you have different types of entities with overlapping fields.
Advantages:
Disadvantages:
Example (MongoDB):
{"_id": ObjectId("64e9f07d1c9667a595f3b1e9"),
"type": "product",
"name": "Laptop",
"price": 1200
}
{"_id": ObjectId("64e9f07e1c9667a595f3b1ea"),
"type": "service",
"name": "Repair",
"duration": "2 hours"
}
Diagram:
graph LR A[Polymorphic Collection] --> B(Product Document); A --> C(Service Document);
The key-value pattern is the simplest document store design. It maps keys to values, suitable for storing simple, frequently accessed data like session data or caching.
Advantages:
Disadvantages: