cheatsheets/mongodb

MongoDB Commands

mongosh is the MongoDB Shell, the JavaScript command line that replaced the legacy mongo shell. This sheet lists the MongoDB commands you type most, from connecting and CRUD to query operators, aggregation, indexes and backups, with one shop database of users and orders in every example.

Updated Oct 12, 2026Tested against MongoDB 9.0, mongosh 2.13, Database Tools 100.19

Connecting

The default port is 27017. Build a URI for your host with the MongoDB connection string generator.

CommandWhat it does
Connect to localhost:27017, database
Connect to a host and open the database
Host and port as flags instead of a URI
Log in as , prompts for the password
Same with flags; with no value prompts
Atlas or any SRV record, TLS on by default
Replica set, sends writes to the primary
TLS with your own CA certificate
Run one command and exit
Start the shell without connecting
Show the current connection string
Log in from inside an open session
Switch to another server or database in a script
Leave the shell ( works too)
Installed mongosh version

Example: connect to a three-node replica set as an app user and confirm which node is primary.

bash
mongosh "mongodb://[email protected],db2.internal,db3.internal/shop?replicaSet=rs0&authSource=admin" \
  --quiet --eval 'db.hello().primary'
# Enter password: ********
# db1.internal:27017

Databases and Collections

A database or collection exists only after the first write, so on a new name creates nothing yet.

CommandWhat it does
List databases with their size on disk
Database names only, also works from scripts
Switch to , created on first write
Print the current database name
List collections and views in the current database
Collection names as an array, for scripts
Query another database without switching
Create a collection explicitly
Create a time series collection
Rename a collection
Data size, storage size and object count for the database
Fast document count from collection metadata
DestructiveDelete the collection, its documents and indexes
DestructiveDelete the current database

Example: add a schema validator to so every document needs an email string.

javascript
use shop
db.runCommand({
  collMod: "users",
  validator: { $jsonSchema: { required: ["email"], properties: { email: { bsonType: "string" } } } },
  validationAction: "error"
})
db.users.insertOne({ name: "No Email" })   // MongoServerError: Document failed validation

Insert

CommandWhat it does
Insert one document; is generated if you leave it out
Insert several documents
Insert the rest after a duplicate key error, then report it
New ObjectId
When an ObjectId was created
Current time as a BSON date
Date from an ISO string
Exact decimal for money, no float rounding
Mix inserts, updates and deletes in one call

A second insert with the same or unique key fails with E11000 duplicate key error.

Example: seed the and collections used on the rest of this page.

javascript
use shop
db.users.insertMany([
  { _id: 7, email: "[email protected]", name: "Ana Ruiz", address: { city: "Berlin" }, signup_at: ISODate("2026-01-10") },
  { _id: 8, email: "[email protected]", name: "Ben Okafor", address: { city: "Lagos" }, signup_at: ISODate("2026-03-02") }
])
db.orders.insertMany([
  { order_no: 1001, user_id: 7, status: "paid", total: 249.9, paid: 249.9, tags: ["gift"],
    items: [{ sku: "SKU-42", qty: 2, price: 99.95 }, { sku: "SKU-7", qty: 1, price: 50 }],
    created_at: ISODate("2026-10-01T09:12:00Z") },
  { order_no: 1002, user_id: 8, status: "pending", total: 89, paid: 0, tags: [],
    items: [{ sku: "SKU-7", qty: 1, price: 89 }],
    created_at: ISODate("2026-08-14T16:40:00Z") },
  { order_no: 1003, user_id: 7, status: "shipped", total: 610, paid: 600, tags: ["gift", "express"],
    items: [{ sku: "SKU-42", qty: 6, price: 101.67 }],
    created_at: ISODate("2026-10-05T11:00:00Z"), shipped_at: ISODate("2026-10-06T08:30:00Z") }
])

Find and Query Operators

takes a filter document. Fields listed side by side are ANDed together.

TaskQuery
All documents (SQL )
First match only
By ObjectId
Equal (SQL )
Not equal (SQL )
Range (, , , )
Any of several values (SQL )
None of several values (SQL )
AND
OR
Date greater than
Field has a value (SQL )
Null or missing (SQL )
Field missing entirely
Contains, any case (SQL ), reads every key
Starts with (SQL ), can use an index
Nested field
Array contains a value
Array contains all values
Array is not empty
Array has exactly N items
One array element meets two conditions
Compare two fields
Wrong type, e.g. totals stored as strings
Count matches (SQL )
Distinct values (SQL )

Without , matches order 1001, where SKU-7 has qty 1 and SKU-42 has qty 2.

Example: Berlin users' paid or shipped orders over 100 from October, excluding express orders.

javascript
const berlin = db.users.distinct("_id", { "address.city": "Berlin" })
db.orders.find({
  user_id: { $in: berlin },
  status: { $in: ["paid", "shipped"] },
  total: { $gt: 100 },
  created_at: { $gte: ISODate("2026-10-01"), $lt: ISODate("2026-11-01") },
  tags: { $ne: "express" }
})

Sort, Limit and Projection

TaskQuery
Return only some fields (SQL )
Return everything except one field
Only the matching array element
Sort descending (SQL )
Sort by two fields
First N (SQL )
Skip N (SQL )
Next page after the last seen
Show the next batch of results
Show more documents per batch
Results as an array, for scripts

Example: the five most recent orders with just the order number, status and total.

javascript
db.orders.find({}, { _id: 0, order_no: 1, status: 1, total: 1 })
  .sort({ created_at: -1 })
  .limit(5)

Update and Delete

and need an operator such as . To swap the whole document, use .

CommandWhat it does
Set fields on the first match
Set fields on every match
Remove a field
Add to a number
Set a field to the current time
Append to an array
Append only if not already present
Remove matching values from an array
Update the array element that matched
Rename a field in every document
Update, or insert if nothing matches
Update and return the new version
Set a field from other fields (pipeline update)
Replace the whole document, keeps
DestructiveDelete the first match
DestructiveDelete every match
DestructiveDelete the oldest match and return it
DestructiveDelete every document, keeps the indexes

Example: upsert a user so the signup date is written only on the first insert, then mark old pending orders cancelled.

javascript
db.users.updateOne(
  { email: "[email protected]" },
  { $set: { name: "Cara Lind" }, $setOnInsert: { signup_at: new Date() } },
  { upsert: true }
)
db.orders.updateMany(
  { status: "pending", created_at: { $lt: new Date(Date.now() - 30 * 24 * 3600 * 1000) } },
  { $set: { status: "cancelled" }, $currentDate: { updated_at: true } }
)

Aggregation

runs the stages in order, each one feeding the next.

TaskStage
Filter (SQL ), put it first so it can use an index
Group and count (SQL )
Group by multiple fields
Sum, average, min, max
Filter on a group result (SQL ) after
Sort (SQL )
Limit and skip,
Pick and compute fields (SQL )
Add a field, keep the rest
One document per array element
Join another collection (SQL )
Count the documents (SQL )
Count per value, sorted
Group by day
Collect values into an array
Latest document per group, then with , see below
Several aggregations in one pass, see below
Write the result to a collection or

Latest order per user, using after a sort:

javascript
db.orders.aggregate([
  { $sort: { created_at: -1 } },
  { $group: { _id: "$user_id", last_order: { $first: "$order_no" }, at: { $first: "$created_at" } } }
])

with a pipeline joins on extra conditions. passes fields from the outer document, used as :

javascript
db.users.aggregate([
  { $lookup: {
      from: "orders",
      let: { uid: "$_id" },
      pipeline: [
        { $match: { $expr: { $eq: ["$user_id", "$$uid"] }, status: { $ne: "cancelled" } } },
        { $sort: { created_at: -1 } },
        { $limit: 3 }
      ],
      as: "recent_orders"
  } }
])

runs sub-pipelines over the same input, handy for a count plus one page of results:

javascript
db.orders.aggregate([
  { $match: { status: { $in: ["paid", "shipped"] } } },
  { $facet: {
      total: [{ $count: "n" }],
      by_status: [{ $sortByCount: "$status" }],
      page: [{ $sort: { created_at: -1 } }, { $limit: 10 }]
  } }
])

In 1bench: the MongoDB GUI builds pipelines stage by stage, with forms for , , , and the other common stages, and a raw JSON mode for anything else.

Example: revenue and units per SKU for paid and shipped orders, joined to the buyer's email.

javascript
db.orders.aggregate([
  { $match: { status: { $in: ["paid", "shipped"] } } },
  { $lookup: { from: "users", localField: "user_id", foreignField: "_id", as: "user" } },
  { $unwind: "$user" },
  { $unwind: "$items" },
  { $group: {
      _id: "$items.sku",
      units: { $sum: "$items.qty" },
      revenue: { $sum: { $multiply: ["$items.qty", "$items.price"] } },
      buyers: { $addToSet: "$user.email" }
  } },
  { $sort: { revenue: -1 } }
])

Indexes

CommandWhat it does
Compound index; field order matters
Reject duplicate values
TTL index, deletes documents an hour after
Index only the documents matching a filter
Text index for search
Search the text index
List indexes with their keys and options
Show the plan, docs examined and time taken
How often each index has been used
Hide an index from the planner before dropping it
Bytes used by all indexes on the collection
Drop one index by name
Drop every index except

In output, means an index was used and means every document was read. Compare with .

In 1bench: the MongoDB GUI shows each collection's indexes with their unique, sparse and TTL settings next to document count and storage size, and creates indexes from a form.

Example: index orders for "this user's latest orders" and confirm the query uses it.

javascript
db.orders.createIndex({ user_id: 1, created_at: -1 })
const plan = db.orders.find({ user_id: 7 }).sort({ created_at: -1 }).explain("executionStats")
plan.queryPlanner.winningPlan                // look for IXSCAN, no SORT stage
plan.executionStats.totalDocsExamined        // should equal nReturned

Scripts

mongosh runs JavaScript, so a script is a file with the same commands you type in the shell.

CommandWhat it does
Run a script file and exit
Same with an explicit flag
Run a script, then stay in the shell
Run a script from inside an open shell
Evaluate one expression, print the result
Print the result as Extended JSON
/ Print from a script
Serialize a document with types kept
Read an environment variable
Pause for one second
Runs on every interactive start (skip with )

Example: a nightly script that archives orders older than a year and prints how many it moved.

javascript
// archive-orders.js, run with: mongosh "mongodb://localhost/shop" archive-orders.js
const cutoff = new Date(Date.now() - 365 * 24 * 3600 * 1000)
db.orders.aggregate([
  { $match: { created_at: { $lt: cutoff } } },
  { $merge: { into: "orders_archive", whenMatched: "keepExisting" } }
])
const res = db.orders.deleteMany({ created_at: { $lt: cutoff } })
print(`archived ${res.deletedCount} orders`)

Backup and Restore

These ship separately from the server as the MongoDB Database Tools. writes BSON; writes JSON or CSV.

CommandWhat it does
Dump one database to a folder of BSON files
Dump every database
Dump one collection
Dump into one compressed file
Dump only matching documents (Extended JSON)
Restore the folder; inserts only, existing s fail
DestructiveDrop each collection before restoring it
Restore into a database with a new name
Restore one collection from a full dump
Import a JSON array file
Import CSV, first line has the field names
Update existing documents by a key, insert the rest
Export one JSON document per line
Export chosen fields as CSV

Example: copy production's database into a local database through one compressed archive.

bash
mongodump --uri "mongodb://[email protected]:27017/shop?authSource=admin" --archive=shop.gz --gzip
mongorestore --uri "mongodb://localhost:27017" --archive=shop.gz --gzip \
  --nsFrom 'shop.*' --nsTo 'shop_staging.*'

Users and Roles

Users live in the database they were created in, usually . Logins then need .

CommandWhat it does
Create a user, prompting for the password
Users defined in the current database
One user's roles and resulting privileges
Built-in and custom roles in the current database
Add a role
Remove a role
Set a new password
Who am I: the logged-in user and roles
Delete a user
Start the server with access control on

Common built-in roles are , , and per database, plus and in .

Example: create a read-only reporting user in that can read and .

javascript
use admin
db.createUser({
  user: "reporting",
  pwd: passwordPrompt(),
  roles: [{ role: "read", db: "shop" }, { role: "read", db: "analytics" }]
})
db.getUser("reporting")

Server and Monitoring

CommandWhat it does
Server version
Node role, primary host and replica set name
Replica set members, state and replication lag
Turn a fresh node into a one-member replica set
Current and available connections
Operations running for 5 seconds or more
Stop an operation by its
Log queries slower than 100 ms to
Latest slow queries
Startup options, config file and
Read and write time per collection every 5 seconds
Inserts, queries, updates and connections per second
DestructiveStop the server, run from

Example: find queries that have been running for more than 10 seconds on and stop them.

javascript
db.currentOp({ secs_running: { $gt: 10 }, ns: /^shop\./ }).inprog.forEach(op => {
  print(`${op.opid} ${op.secs_running}s ${op.ns}`)
  db.killOp(op.opid)
})

Gotchas

  • matches documents where the field is null and documents that do not have it at all. Add when you only want explicit nulls.
  • Types must match. does not find , and does not find an ObjectId. Wrap it in .
  • removes every document but keeps the collection and its indexes, while removes both. Neither can be undone without a backup.
  • fails in mongosh because the update has no operator. with the same document replaces every field.
  • only inserts. Documents whose already exists fail as duplicate keys and keep their current values, so a restore over live data silently mixes old and new. Restore into a new database with , or use .
  • The legacy shell was removed in MongoDB 6.0, and its and helpers are deprecated in mongosh. Use and or .

Work with MongoDB without memorizing it

1bench is a desktop GUI for MongoDB. Connect, browse your data and run queries in one window, with the CLI still there when you want it.

Open MongoDB in 1bench

MongoDB FAQ

Where does MongoDB store data?
In the directory set by storage.dbPath, as WiredTiger files with generated names, not one file per collection. A mongod started with no setting uses /data/db, Linux packages use /var/lib/mongodb and Homebrew on Apple silicon uses /opt/homebrew/var/mongodb. To see what a running server uses, run db.adminCommand({ getCmdLineOpts: 1 }) and read parsed.storage.dbPath. Back up with mongodump or a filesystem snapshot, never by copying the files of a running server.
Can MongoDB do joins?
Yes, with the $lookup aggregation stage. It works like a SQL LEFT OUTER JOIN: every input document comes out with an array of matches, empty when nothing matched. Follow it with $unwind to get one document per match, and drop the empty ones for INNER JOIN behavior. Index the foreignField on the joined collection, since $lookup runs a query against it for each input document.
Does MongoDB support transactions?
Yes. Multi-document ACID transactions work on replica sets since 4.0 and on sharded clusters since 4.2. A standalone mongod rejects them, so for local testing start it with --replSet rs0 and run rs.initiate() once. In mongosh, call db.getMongo().startSession(), then session.startTransaction(), run your writes through session.getDatabase("shop"), and finish with commitTransaction() or abortTransaction(). Writes to a single document are atomic without a transaction.
How do I compare two fields in the same document?
Wrap an aggregation expression in $expr inside a normal find filter: db.orders.find({ $expr: { $lt: ["$paid", "$total"] } }) returns orders paid for less than their total. Plain query operators only compare a field with a constant, so { paid: { $lt: "$total" } } compares against the literal string "$total" and silently matches nothing. $expr also works in $match and can mix in date and math operators.
How does MongoDB generate an ObjectId?
The driver or shell builds it on the client, not the server. An ObjectId is 12 bytes: a 4-byte Unix timestamp in seconds, a 5-byte random value per process and a 3-byte counter. ObjectId("...").getTimestamp() returns the creation time, and sorting by _id gives roughly insertion order. Do not treat it as exact order across machines, since clocks and counters differ between clients.