Mastering One-to-Many via References
In this lesson, you will learn how to connect independent collections by using manual application-level joins to link parent documents to their many children.
While embedding data directly into a document is efficient for read-heavy workloads, it isn't always the best fit. If a parent document (like an Author) can have thousands of related Books, embedding them all would lead to massive, unwieldy documents that constantly hit size limits. Instead, we use References.
The Reference Pattern
When we use references, we treat the two collections as independent entities. Each Book document stores the _id of its parent Author. This is essentially a "Foreign Key" at the application level.
Consider these two collections:
Collection: authors
{ "_id": 1, "name": "Jane Doe" }
Collection: books
{ "_id": 101, "title": "Database Basics", "author_id": 1 },
{ "_id": 102, "title": "Advanced NoSQL", "author_id": 1 }
Performing Manual Application-Level Joins
Since NoSQL databases do not perform relational joins automatically, you must bridge these collections in your application logic. To retrieve an author along with all their books, your application performs a two-step process:
- Query the parent: Fetch the
Authordocument using their ID. - Query the children: Execute a second query against the
bookscollection using thatauthor_id.
// Pseudocode for the join
const author = db.authors.findOne({ _id: 1 });
const books = db.books.find({ author_id: author._id }).toArray();
// The application combines them into one object
const result = { ...author, books: books };
This approach keeps your individual document sizes small and manageable. By decoupling the parent and child, you ensure that adding a new book doesn't require modifying the author’s document, which is critical when a parent has a "growing" or unbounded number of children. However, remember that you trade off the convenience of a single-read operation for the flexibility of independent document growth.
Key Takeaway: Use references when your child data is unbounded or accessed independently, then use application logic to bridge the two collections via a common ID.