Mongoose/Mongo Advance Concepts
- Relationship types
- Referencing/Normalization vs Embedding/Denormalization
- Embedding or Referencing Documents
- Types of referencing
- Parent Referencing
- Child Referencing
- Two-Way Referencing
Relationship Types:
1:1
In systems analysis, a one-to-one relationship is a type of cardinality that refers to the relationship between two entities A and B in which one element of A may only be linked to one element of B, and vice versa. In mathematical terms, there exists a bijective function from A to B
1:MANY
In systems analysis, a one-to-many relationship is a type of cardinality that refers to the relationship between two entities A and B in which an element of A may be linked to many elements of B, but a member of B is linked to only one element of A. For instance, think of A as books, and B as pages.
MANY:MANY
In systems analysis, a many-to-many relationship is a type of cardinality that refers to the relationship between two entities, say, A and B, where A may contain a parent instance for which there are many children in B and vice versa. For example, think of A as Authors, and B as Books
Referencing VS Embedding
Referenced / Normalized
When you normalize your data, you are dividing your data into multiple collections with references between those collections. Each piece of data will be in a collection, but multiple documents will reference it
๐ Easy to query each document on its own.
๐ Need 2 queries to get data from the referenced document.
Embedding / Denormalization
Denormalization allows you to avoid some application-level joins, at the expense of having more complex and expensive updates.
๐ We can get all info in one query.
๐ Cannot query the embedded document on its own.
When to Embed & When to Refer?
Before finalizing your decision to embed or refer to the document first check these three criteria.
Relationship Types
For many:many or one:many types Referencing is preferred.
Data Access Patterns
If data is updated a lot or the read/write ratio is low go with Referencing else go with embedding
Data Closeness
How much is data related? For example how many movies & images are associated with each other? If images are frequently queried with movies go with reference.
Types of Referencing
Child Referencing
Main Parent document. You can see the object IDs of the child documents are referred to in the parent documents. Use this referencing in case of 1:FEW
{
"_id" : ObjectID('23'),
"app": "My Movie Database",
"logs": [
ObjectID('1'),
ObjectID('2'),
// ... Millions of ObjectID
ObjectID('28273927')
]
}
Child Document.
{
"_id": ObjectID('1'),
"type": "error",
"timestamp": 1412184926
}
Child Document.
{
"_id " : ObjectID('28273927'),
"type": "error",
"timestamp": 1412844672
}
๐ But there is still one problem. If there are millions of child objects. Each one has to be referred to in the parent object causing an increase in the size of the parent document. The maximum BSON document size is 16 megabytes.
Parent Referencing
Now instead of saving the object ids of all the child documents in the parent, we can save the objectId
of the parent document in each child. That will solve the problem of increasing size. If you are using one:many
or one:ton
you can use this referencing.
// PARENT
{
"_id" : ObjectID('23'),
"app": "My Movie Database"
}
// CHILD
{
"_id": ObjectID('1'),
"app": ObjectID('23'),
"type": "error",
"timestamp": 1412184926
}
// CHILD
{
"_id": ObjectID('28273927'),
"app": ObjectID('23'),
"type": "error",
"timestamp": 1412844672
}
TWO-WAY Referencing
So if there is a case you are using many:many
relationship types you can prefer this type of reference.
// PARENT
{
"_id": ObjectID('23'),
"title": "Interstellar",
"release Year: 2014,
"actors": [
ObjectID('67'),
// ... and many more
]
}
// CHILD
{
"_id": ObjectID('67'),
"name": "Matthew McConaughey",
"age": 50,
"movies": [
ObjectID('23'),
// ... and many more
]
}
Populating Documents
One more thing you need to take care of after referencing your documents is to populate them. To get all the entities it is better to populate the document first.
- Population
Populating when using child referencing.
findOne({ title: 'Casino Royale' }).populate('author').
Virtual Populate
Populating parent when using parent referencing
// Specifying a virtual with a `ref` property is how you enable virtual // population AuthorSchema.virtual('posts', { ref: 'BlogPost', localField: '_id', foreignField: 'author' });
For a more detailed explanation refer to the documentation
https://mongoosejs.com/docs/populate.html#populate-virtuals
Acknowledgment
- This node.js course helped me implement the above code node.js bootcamp
Originally published at theundersurfers.netlify.app