Reference data
Reference data
Relational databases aren't the only place where you can create relationships between entities. In a document database, you may have information in one document that relates to data in other documents.
In the JSON below we chose to use the example of a stock portfolio from earlier but this time we refer to the stock item on the portfolio instead of embedding it. This way, when the stock item changes frequently throughout the day the only document that needs to be updated is the single stock document.
Stocks portfolio example
An immediate downside to this approach though is if your application is required to show information about each stock that is held when displaying a person's portfolio; in this case you would need to make multiple trips to the database to load the information for each stock document.
Here we've made a decision to improve the efficiency of write operations, which happen frequently throughout the day, but in turn compromised on the read operations that potentially have less impact on the performance of this particular system.
Normalized data models can require more round trips to the server.
Because there's currently no concept of a constraint, foreign-key or otherwise, any inter-document relationships that you have in documents are effectively "weak links" and won't be verified by the database itself. If you want to ensure that the data a document is referring to actually exists, then you need to do this in your application!
Where do I put the relationship?
The growth of the relationship will help determine in which document to store the reference.
If we look at the JSON below that models publishers and books.
If the number of the books per publisher is small with limited growth, then storing the book reference inside the publisher document may be useful. However, if the number of books per publisher is unbounded, then this data model would lead to mutable, growing arrays, as in the example publisher document above.
Switching things around a bit would result in a model that still represents the same data but now avoids these large mutable collections.
In the above example, we've dropped the unbounded collection on the publisher document. Instead we just have a reference to the publisher on each book document.
How do I model many-to-many relationships?
In a relational database many-to-many relationships are often modeled with join tables, which just join records from other tables together.
You might be tempted
You might be tempted to replicate the same thing using documents and produce a data model that looks similar to the following.
This would work. However, loading either an author with their books, or loading a book with its author, would always require at least two additional queries against the database. One query to the joining document and then another query to fetch the actual document being joined.
If this join is only gluing together two pieces of data, then why not drop it completely? Consider the following example.
Better design
Now, if I had an author, I immediately know which books they've written, and conversely if I had a book document loaded, I would know the IDs of the author(s). This saves that intermediary query against the join table reducing the number of server round trips your application has to make.
Hybrid data models
We've now looked at embedding (or denormalizing) and referencing (or normalizing) data. Each approach has upsides and compromises.
It doesn't always have to be either-or, don't be scared to mix things up a little.
Based on your application's specific usage patterns and workloads there may be cases where mixing embedded and referenced data makes sense and could lead to simpler application logic with fewer server round trips while still maintaining a good level of performance.
Consider the following JSON.
Here we've (mostly) followed the embedded model, where data from other entities are embedded in the top-level document, but other data is referenced.
Every time a new book is published, a book document is created and the countOfBooks
field is set to a calculated value based on the number of book documents that exist for a particular author. This optimization would be good in read heavy systems!
Last updated