Now that we understood the way we can design our documents, let's take some examples of real-life problems, such as how to write a data model that better describes the relationship between entities.
This section will present you with patterns that illustrate when to embed or when to reference documents. Until now, we have considered as a deciding factor:
One-to-one relationships are simpler than the others. Most of the time, we will map this relationship with embedded documents, especially if it is a "contains" relationship.
The following example shows a customer's document. In the first case, there is a reference in a customerDetails
document; in the second, we see a reference with embedded data:
customer { "_id": 5478329cb9617c750245893b "username" : "John Clay", "email": "[email protected]", "password": "bf383e8469e98b44895d61b821748ae1" } customerDetails { "customer_id": "5478329cb9617c750245893b", "firstName": "John", "lastName": "Clay", "gender": "male", "age": 25 }
customer { _id: 1 "username" : "John Clay", "email": "[email protected]", "password": "bf383e8469e98b44895d61b821748ae1" "details": { "firstName": "John", "lastName": "Clay", "gender": "male", "age": 25 } }
The advantage of representing the relationship with an embedded document is that the customer detail data is always available when we query a customer. Thus, we can say that a customer's details do not make sense by themselves, only alongside the customer data.
One-to-many relationships are more complex than one-to-one relationships. In order to decide when to embed or to make references, we must consider the "many" side of the relationship. If the many side should be displayed with its parents, then we should choose to embed the data; otherwise, we can use references on the parents.
Let's see an example of customer
and the customer's address:
customer { _id: 1 "username" : "John Clay", "email": "[email protected]", "password": "bf383e8469e98b44895d61b821748ae1" "details": { "firstName": "John", "lastName": "Clay", "gender": "male", "age": 25 } } address { _id: 1, "street": "Address 1, 111", "city": "City One", "state": "State One", "type": "billing", "customer_id": 1 } { _id: 2, "street": "Address 2, 222", "city": "City Two", "state": "State Two", "type": "shipping", "customer_id": 1 } { _id: 3, "street": "Address 3, 333", "city": "City Three", "state": "State Three", "type": "shipping", "customer_id": 1 }
If, every time you want to display a customer's address, you also need to display the customer's name, then embedded documents are recommended:
customer { _id: 1 "username" : "John Clay", "email": "[email protected]", "password": "bf383e8469e98b44895d61b821748ae1" "details": { "firstName": "John", "lastName": "Clay", "gender": "male", "age": 25 } "billingAddress": [{ "street": "Address 1, 111", "city": "City One", "state": "State One", "type": "billing", }], "shippingAddress": [{ "street": "Address 2, 222", "city": "City Two", "state": "State Two", "type": "shipping" }, { "street": "Address 3, 333", "city": "City Three", "state": "State Three", "type": "shipping" }] }
A many-to-many relationship is not something trivial, even in a relational universe. In the relational world, this kind of relationship is often represented as a join table while, in the non-relational one, it can be represented in many different ways.
In the following code, we will see a classic example of a user
and group
relation:
user { _id: "5477fdea8ed5881af6541bf1", "username": "user_1", "password" : "3f49044c1469c6990a665f46ec6c0a41" } { _id: "54781c7708917e552d794c59", "username": "user_2", "password" : "15e1576abc700ddfd9438e6ad1c86100" } group { _id: "54781cae13a6c93f67bdcc0a", "name": "group_1" } { _id: "54781d4378573ed5c2ce6100", "name": "group_2" }
Now let's store the relationship in the User
document:
user { _id: "5477fdea8ed5881af6541bf1", "username": "user_1", "password" : "3f49044c1469c6990a665f46ec6c0a41", "groups": [ { _id: "54781cae13a6c93f67bdcc0a", "name": "group_1" }, { _id: "54781d4378573ed5c2ce6100", "name": "group_2" } ] } { _id: "54781c7708917e552d794c59", "username": "user_2", "password" : "15e1576abc700ddfd9438e6ad1c86100", "groups": [ { _id: "54781d4378573ed5c2ce6100", "name": "group_2" } ] } group { _id: "54781cae13a6c93f67bdcc0a", "name": "group_1" } { _id: "54781d4378573ed5c2ce6100", "name": "group_2" }
Or we can store the relationship in the group
document:
user { _id: "5477fdea8ed5881af6541bf1", "username": "user_1", "password" : "3f49044c1469c6990a665f46ec6c0a41" } { _id: "54781c7708917e552d794c59", "username": "user_2", "password" : "15e1576abc700ddfd9438e6ad1c86100" } group { _id: "54781cae13a6c93f67bdcc0a", "name": "group_1", "users": [ { _id: "54781c7708917e552d794c59", "username": "user_2", "password" : "15e1576abc700ddfd9438e6ad1c86100" } ] } { _id: "54781d4378573ed5c2ce6100", "name": "group_2", "users": [ { _id: "5477fdea8ed5881af6541bf1", "username": "user_1", "password" : "3f49044c1469c6990a665f46ec6c0a41" }, { _id: "54781c7708917e552d794c59", "username": "user_2", "password" : "15e1576abc700ddfd9438e6ad1c86100" } ] }
And, finally, let's store the relationship in both documents:
user { _id: "5477fdea8ed5881af6541bf1", "username": "user_1", "password" : "3f49044c1469c6990a665f46ec6c0a41", "groups": ["54781cae13a6c93f67bdcc0a", "54781d4378573ed5c2ce6100"] } { _id: "54781c7708917e552d794c59", "username": "user_2", "password" : "15e1576abc700ddfd9438e6ad1c86100", "groups": ["54781d4378573ed5c2ce6100"] } group { _id: "54781cae13a6c93f67bdcc0a", "name": "group_1", "users": ["5477fdea8ed5881af6541bf1"] } { _id: "54781d4378573ed5c2ce6100", "name": "group_2", "users": ["5477fdea8ed5881af6541bf1", "54781c7708917e552d794c59"] }
52.15.65.65