Collections
A collection is MongoDB's analog of a relational table: a named group of documents inside a database. Unlike a table, a collection does not enforce a schema by default — documents in the same collection can have different fields. This page covers creating, configuring, renaming, listing, and dropping collections.
Implicit Creation
Like databases, collections spring into existence on first use. Inserting into a collection that does not exist creates it automatically:
Implicit creation
use shop
show collections // (empty)
db.products.insertOne({ name: "Keyboard", price: 79.99 })
show collectionsproducts
Creating an index on a non-existent collection also creates it. Implicit creation is convenient, but it means a typo (db.prodcuts.find()) silently queries an empty collection instead of erroring.
Explicit Creation with createCollection
db.createCollection() creates a collection up front. You only need it when you want to pass options — validators, capped sizing, collation, or time-series configuration.
createCollection
// Plain explicit creation (rarely needed)
db.createCollection("orders")
// With options — this is why explicit creation exists
db.createCollection("orders", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["orderNumber", "total"],
properties: {
orderNumber: { bsonType: "int" },
total: { bsonType: ["double", "int", "decimal"], minimum: 0 }
}
}
},
validationLevel: "strict", // apply to all inserts and updates
validationAction: "error" // reject invalid documents (vs "warn")
})Collection Options
Option | Purpose |
|---|---|
validator | JSON Schema (or query expression) that documents must satisfy |
validationLevel | 'strict' (default) or 'moderate' (only validate documents that already pass) |
validationAction | 'error' (reject) or 'warn' (log and allow) |
capped, size, max | Create a fixed-size capped collection |
collation | Default string-comparison rules (locale, case sensitivity) |
timeseries | Create a time-series collection (metaField, timeField, granularity) |
expireAfterSeconds | TTL for time-series / clustered collections |
Capped Collections
A capped collection has a fixed maximum size. Once full, the oldest documents are overwritten by new ones — a built-in circular buffer. Insertion order is preserved, making them ideal for logs and recent-activity feeds.
Creating and using a capped collection
db.createCollection("recentEvents", {
capped: true,
size: 10 * 1024 * 1024, // max bytes (required) — 10 MB
max: 10000 // optional: max number of documents
})
db.recentEvents.insertOne({ type: "login", userId: 42, at: new Date() })
// Documents come back in insertion order (natural order)
db.recentEvents.find()
// Check whether a collection is capped
db.recentEvents.isCapped() // trueDefault Collation
Collation controls how strings compare and sort. Setting it at creation time makes every query, sort, and index on the collection case-insensitive (or locale-aware) by default:
Case-insensitive collection
db.createCollection("customers", {
collation: { locale: "en", strength: 2 } // strength 2 = ignore case
})
db.customers.insertOne({ name: "Alice" })
// Matches despite the different case — collection collation applies
db.customers.find({ name: "alice" })Listing Collections
Listing and inspecting
show collections // mongosh shorthand
db.getCollectionNames() // array of names
db.getCollectionInfos() // names + options + info
db.getCollectionInfos({ name: "orders" }) // filter to one collection
db.orders.stats() // size, count, index details
db.orders.countDocuments() // accurate document count[
{
name: 'orders',
type: 'collection',
options: { validator: { ... }, validationLevel: 'strict' },
info: { readOnly: false, uuid: UUID('8a1c...') },
idIndex: { v: 2, key: { _id: 1 }, name: '_id_' }
}
]Renaming a Collection
renameCollection
// Rename within the same database
db.orders.renameCollection("orders_archive")
// Overwrite an existing target collection
db.orders_new.renameCollection("orders", true) // dropTarget = trueRenaming keeps all documents and indexes intact.
You cannot rename across databases with this helper (use
$outin aggregation or dump/restore instead).Renaming is not allowed on sharded collections in older versions; check your server version's documentation before relying on it.
Dropping a Collection
drop
db.orders_archive.drop()
true
drop() removes the collection, all of its documents, and all of its indexes. Compare that with deleteMany({}), which removes documents but keeps the collection and its indexes:
Operation | Documents | Indexes | Collection options | Speed |
|---|---|---|---|---|
db.coll.deleteMany({}) | Removed | Kept | Kept | Slow (one-by-one) |
db.coll.drop() | Removed | Removed | Removed | Fast (metadata operation) |
Collection Naming Rules
Names must not be empty, must not contain the null character, and must not start with
system.(reserved prefix).Avoid the dollar sign in names — it is reserved in most contexts.
Names including dots (
orders.archive) are legal but confusing in shell helpers; prefer camelCase or snake_case instead.The full namespace (
database.collection) has a length limit (255 bytes in modern versions); keep names reasonably short.Convention: plural nouns for entity collections —
users,orders,products.
Accessing awkward names
// If a name clashes with a shell property or contains odd characters:
db.getCollection("weird-name.v2").find()
db["weird-name.v2"].countDocuments()Views
A view is a read-only, aggregation-defined collection. It stores no data; queries against it run the underlying pipeline on the fly:
Creating a view
db.createView(
"activeCustomers", // view name
"customers", // source collection
[ { $match: { status: "active" } },
{ $project: { name: 1, email: 1 } } ]
)
db.activeCustomers.find({ name: /^A/ }) // queries the view like a collectionSummary
Collections group documents inside a database and are created implicitly on first insert or index build.
Use
db.createCollection()when you need options: validators, capped sizing, collation, or time-series settings.Capped collections are fixed-size circular buffers with strict limitations — TTL indexes are usually the better expiry tool.
renameCollectionpreserves data and indexes;drop()removes everything including indexes and options.Views expose an aggregation pipeline as a read-only collection.