MongoDBDocuments & Collections Relationship

Documents & Collections

MongoDB stores data as documents grouped into collections. A document is a single record — the rough equivalent of a row in a relational table — encoded as BSON (Binary JSON). A collection is a named group of documents — the rough equivalent of a table — except a collection places no fixed schema on the documents it holds.

Understanding the document/collection relationship is the foundation for everything else in MongoDB: querying, indexing, and data modeling all build on top of it.

What a Document Looks Like

A document is an ordered set of key-value pairs, written as BSON on disk and rendered as JSON-like syntax in mongosh. Keys are strings; values can be any BSON type, including other documents and arrays.

A single document

JS
{
  _id: ObjectId("64f1a2b3c4d5e6f7a8b9c0d1"),
  name: "Alice Chen",
  email: "alice@example.com",
  age: 29,
  active: true,
  tags: ["admin", "beta-tester"],
  address: {
    city: "Toronto",
    country: "CA"
  },
  createdAt: ISODate("2024-01-15T10:30:00Z")
}

Every document has exactly one _id field, which acts as its primary key within the collection. If you don't supply one on insert, MongoDB generates an ObjectId automatically.

The _id Field
  • _id must be unique within a collection — MongoDB enforces this with an automatic index on _id created the moment the collection exists.

  • It is immutable — once a document is inserted, you cannot change its _id with an update; you would have to delete and re-insert.

  • It can be any BSON type — an ObjectId (the default), a string, a number, or even a compound (embedded document) key.

  • It is always the first field returned unless explicitly excluded in a projection.

Custom _id values

JS
// Natural key instead of an auto-generated ObjectId
db.currencies.insertOne({ _id: "USD", name: "US Dollar", symbol: "$" })

// Compound _id built from multiple business fields
db.inventory.insertOne({
  _id: { warehouse: "YYZ", sku: "WIDGET-42" },
  qty: 500
})
Field Types Are Flexible

Unlike a relational table, a collection has no built-in requirement that every document share the same fields or field types. Two documents in the same collection can legally look completely different.

Heterogeneous documents in one collection

JS
db.products.insertMany([
  { name: "Widget", price: 9.99, stock: 100 },
  { name: "Gadget", price: "24.50 CAD", onSale: true },   // price is a string here
  { name: "Gizmo", variants: [{ color: "red" }, { color: "blue" }] }
])
Warning
Schema flexibility is a tool, not a free pass. Most production apps enforce a consistent shape at the application layer, and often add a $jsonSchema validator on the collection to reject documents that drift too far from the expected structure.
Nested Documents and Arrays

The ability to embed documents and arrays inside a document is what lets MongoDB model rich, hierarchical data without joins. This is the biggest structural difference from a normalized relational schema.

Embedding related data

JS
{
  _id: ObjectId("64f1a2b3c4d5e6f7a8b9c0d2"),
  orderNumber: "ORD-1042",
  customer: {                       // embedded (sub-)document
    name: "Bob Ivanov",
    email: "bob@example.com"
  },
  items: [                          // array of embedded documents
    { sku: "WIDGET-42", qty: 2, price: 9.99 },
    { sku: "GADGET-7",  qty: 1, price: 24.50 }
  ],
  tags: ["priority", "gift-wrap"],  // array of scalars
  total: 44.48
}

Pattern

When to Use

Tradeoff

Embed (nest)

Data is read together and belongs to a "contains" relationship (order + its line items).

Duplicated data across documents if the embedded value is shared; document can grow large.

Reference (store an _id)

Data is large, shared across many parents, or updated independently (a product catalog referenced from many orders).

Requires a $lookup or a second query to resolve the reference.

The 16 MB Document Size Limit

Every BSON document is capped at 16 MB. This limit exists so a single document can always fit comfortably in RAM and be transferred efficiently over the wire — MongoDB is not designed for documents that grow unbounded.

Checking a document's BSON size

JS
const doc = db.orders.findOne({ orderNumber: "ORD-1042" })
Object.bsonsize(doc)   // returns the size in bytes
Note
If a document is approaching or exceeding 16 MB, that's usually a modeling smell — an unbounded array (comments, log entries, sensor readings) growing inside a single document. The fix is almost always to move that unbounded data into its own collection and reference the parent's _id.
What a Collection Is

A collection is created implicitly the first time you insert a document into it (or explicitly with db.createCollection() when you need options like schema validation, capped size, or a specific collation up front).

Creating and inspecting collections

JS
// Implicit creation — the collection appears on first insert
db.reviews.insertOne({ productId: "WIDGET-42", rating: 5 })

// Explicit creation with options
db.createCollection("auditLog", {
  capped: true,
  size: 5 * 1024 * 1024,   // 5 MB max size
  max: 10000               // and/or a max document count
})

db.getCollectionNames()
db.reviews.drop()   // removes the collection and its indexes entirely
Thinking About Collection Design
  • Group by access pattern, not by "entity." Ask "what data do I read together, most often?" before asking "what are my nouns?"

  • One collection per bounded, independently-queried entity typeusers, orders, products — rather than one giant collection holding everything.

  • Avoid unbounded growth inside a single document. Time-series events, comments, or logs that grow forever belong in their own collection, often with the parent id as a foreign key.

  • Favor duplication over indirection when reads dominate writes. MongoDB doesn't optimize for normalization the way SQL does — a little denormalization for read speed is idiomatic, not a hack.

Databases, Collections, Documents — the Hierarchy
test> show dbs
admin    100.00 KiB
config   72.00 KiB
ecommerce 2.31 MiB
local     72.00 KiB

test> use ecommerce
switched to db ecommerce

ecommerce> show collections
orders
products
reviews

ecommerce> db.products.countDocuments()
248

ecommerce> db.products.findOne()
{
  _id: ObjectId('64f1a2b3c4d5e6f7a8b9c0d1'),
  name: 'Blue Widget',
  price: 9.99,
  stock: 500
}
Tip
Database → Collection → Document is the full hierarchy. A single MongoDB deployment can host many databases; each database holds many collections; each collection holds many documents. There is no equivalent of a SQL "schema" namespace between database and collection — collection names are flat within a database.