Start with the résumé document from the last lesson. Watch what happens as requirements arrive.
“Company pages should have a logo and a description.” Companies are now
entities. You add a companies collection and put companyId on each position.
That is one reference.
“Show everyone who worked at Acme.” You query positions by companyId, get
a list of person ids, then fetch those people. That is a join, executed by your
code, in a loop.
“Recommend people who worked at the same company at overlapping times.” Now you are joining positions to positions through companies, with a date-range predicate.
The idea
Nothing about the document model prevented any of this. It just moved the join
from the database — which has a query planner, statistics, and thirty years of
work on join algorithms — into your application, which has a for loop.
Why this direction is one-way
The pressure only ever runs toward more references, because the forces that create many-to-many relationships are the ordinary forces of a product growing up:
- Something that was a string becomes an entity. A tag needs a colour. An industry needs a canonical list. A skill needs to be searchable. Every one of these turns an embedded value into a shared record.
- Someone asks a question in the reverse direction. You stored positions under people; they want people under companies.
- A rule needs to hold across records. “No two employees can have the same badge number” cannot be enforced inside a single document, because the document does not know about the others.
You will not find the reverse pressure. Nothing in a maturing product says “actually, let us make this entity into a duplicated string again.”
This argument is older than you think
Where the line actually is
This is not an argument that documents are wrong. It is an argument about which question you are answering.
Documents fit when the relationships are a tree, you load the tree whole, and the shape varies between records. Event payloads, product catalogues with wildly different attributes, activity logs, anything write-once.
Relations fit when entities are shared, queries run in several directions, and rules must hold across records. Anything with users, permissions, money, or reporting — which is most business software.
The honest summary
Choose the document model when your data really is a tree and you know which way the queries run. Choose the relational model when you expect to be surprised.
Check yourself
A document store holds `projects`, each embedding an array of team-member objects with name and role. What is the clearest sign the model has outgrown itself?
What to take away
Many-to-many is where document models start paying rent. The joins do not go away when you leave the relational model; they move somewhere with less information and worse tooling. Decide whether you want them written in SQL by a planner, or in JavaScript by you.