Skip to content
Course contents

Many-to-Many Brings the Joins Back

Every document model eventually grows a reference, then a second one, then an application-level join loop. This is the oldest argument in databases and it has already happened twice.

Lesson 3 of 510 min read

By the end of this lesson you can

  • Recognise the point at which a document model has quietly become a relational one
  • Explain why joins move to the application rather than disappearing
  • Give the historical reason relational databases won the first time this argument happened

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.

If you want to go deeper

Finished this one?

skip for now