Writing application code is not the only way to interact with MongoDB. The MongoDB Shell (mongosh) is the command-line REPL that lets you query, inspect, and administer your database directly — essential for debugging in production, running one-off migrations, inspecting query performance, and exploring unfamiliar data. MongoDB Compass is the official GUI that visualises your collections, lets you run queries with autocomplete, explains query plans graphically, and manages indexes without typing a single command. Every backend developer needs both tools in their toolkit — they complement your application code and save enormous time during development and operations.
MongoDB Shell (mongosh) Key Commands
| Command | Description |
|---|---|
mongosh |
Connect to local MongoDB on default port 27017 |
mongosh "mongodb+srv://..." |
Connect to Atlas or a remote server |
show dbs |
List all databases with sizes |
use taskmanager |
Switch to (or create) a database |
show collections |
List all collections in current database |
db.tasks.find() |
Query the tasks collection |
db.tasks.countDocuments() |
Count all documents in collection |
db.tasks.drop() |
Delete the entire collection |
db.dropDatabase() |
Delete the current database |
db.tasks.getIndexes() |
List all indexes on a collection |
db.tasks.stats() |
Collection statistics — size, count, index sizes |
db.tasks.explain('executionStats').find({}) |
Show query execution plan and stats |
exit |
Exit mongosh |
MongoDB Compass Features
| Feature | What It Does | When to Use |
|---|---|---|
| Schema Tab | Analyse field types and value distributions in a collection | Exploring a new dataset or debugging data quality issues |
| Documents Tab | Browse, filter, insert, edit, and delete documents visually | Inspecting and debugging specific records |
| Explain Plan | Visualises query execution — shows index use vs collection scans | Performance tuning — checking if indexes are being used |
| Indexes Tab | View, create, and drop indexes with usage statistics | Index management — which indexes exist, how often used |
| Aggregations | Build aggregation pipelines stage-by-stage with live preview | Developing complex aggregation queries iteratively |
| Performance Tab | Real-time monitoring — operations per second, slow queries | Production monitoring (Compass connected to Atlas) |
| Shell (embedded) | Full mongosh shell inside the GUI | Quick commands without switching applications |
db.collection.find() in mongosh returns a cursor that automatically batches results. The shell shows the first 20 documents and waits. Type it (short for “iterate”) to see the next batch. When scripting in mongosh, always call .toArray() to get all results at once, or use forEach() to process documents one at a time without loading them all into memory: db.tasks.find().forEach(doc => print(doc.title)).winningPlan section. If you see COLLSCAN (collection scan), the query scans every document — it needs an index. If you see IXSCAN (index scan), it is already using an index efficiently. The “Examined vs Returned” ratio tells you how many documents MongoDB scanned to return the ones you wanted — a ratio of 1:1 is ideal; a ratio of 1000:1 means you need a better index.db.dropDatabase() or db.collection.drop() in a production mongosh session without a confirmed backup. MongoDB has no recycle bin. These commands are instantaneous and irreversible. Always set an environment variable or shell alias that reminds you which environment you are connected to, and double-check before running any destructive command. For Atlas, enable Point-in-Time Restore before running migrations.mongosh Practical Session
// ── Starting mongosh ──────────────────────────────────────────────────────
// Local: mongosh
// Atlas: mongosh "mongodb+srv://username:password@cluster.mongodb.net/taskmanager"
// ── Database navigation ───────────────────────────────────────────────────
show dbs // list all databases
use taskmanager // switch database
show collections // list collections: users, tasks, sessions
// ── Querying data ─────────────────────────────────────────────────────────
db.tasks.find() // show first 20 tasks
db.tasks.find({ status: 'pending' }) // filter
db.tasks.findOne({ _id: ObjectId('64a1f2b3c8e4d5f6a7b8c9d0') })
// Pretty-print a document
db.tasks.findOne().pretty ? db.tasks.findOne().pretty() : db.tasks.findOne()
// Count documents
db.tasks.countDocuments({ status: 'pending', priority: 'high' })
// Distinct values of a field
db.tasks.distinct('status') // ['pending', 'in-progress', 'completed']
db.tasks.distinct('priority') // ['low', 'medium', 'high']
// ── Sorting, limiting, projecting ─────────────────────────────────────────
db.tasks
.find({ userId: ObjectId('64a1f2b3c8e4d5f6a7b8c9d1') })
.sort({ createdAt: -1 })
.limit(5)
.projection({ title: 1, status: 1, _id: 0 })
// ── Creating and updating ──────────────────────────────────────────────────
db.tasks.insertOne({
title: 'Test task from shell',
status: 'pending',
priority: 'medium',
userId: ObjectId('64a1f2b3c8e4d5f6a7b8c9d1'),
createdAt: new Date(),
})
db.tasks.updateOne(
{ title: 'Test task from shell' },
{ $set: { status: 'completed', completedAt: new Date() } }
)
db.tasks.deleteOne({ title: 'Test task from shell' })
// ── Collection statistics ─────────────────────────────────────────────────
db.tasks.stats()
// { ns, count, size, avgObjSize, storageSize, nindexes, indexSizes, ... }
db.tasks.getIndexes()
// [{ v, key, name }, { v, key: { userId: 1, createdAt: -1 }, name: 'userId_1_createdAt_-1' }]
// ── Query performance analysis ────────────────────────────────────────────
db.tasks.explain('executionStats').find({ status: 'pending', userId: ObjectId('...') })
// Look for:
// winningPlan.inputStage.stage — 'IXSCAN' (good) or 'COLLSCAN' (needs index)
// executionStats.totalDocsExamined — how many docs scanned
// executionStats.nReturned — how many docs returned
// executionStats.executionTimeMillis — query time in ms
// ── Index management ──────────────────────────────────────────────────────
// Create a compound index
db.tasks.createIndex({ userId: 1, createdAt: -1 })
db.tasks.createIndex({ title: 'text', description: 'text' }) // text search index
// Drop an index
db.tasks.dropIndex('userId_1_createdAt_-1')
// ── Bulk operations ───────────────────────────────────────────────────────
// Update all pending tasks older than 30 days to 'stale' status
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
db.tasks.updateMany(
{ status: 'pending', createdAt: { $lt: thirtyDaysAgo } },
{ $set: { status: 'stale', updatedAt: new Date() } }
)
// ── Running JavaScript in mongosh ──────────────────────────────────────────
// mongosh is a full JavaScript REPL — you can write scripts
const result = db.tasks.aggregate([
{ $group: { _id: '$status', count: { $sum: 1 } } },
{ $sort: { count: -1 } }
]).toArray()
result.forEach(r => print(`${r._id}: ${r.count}`))
Connecting to Atlas in mongosh
# Connect to Atlas (get connection string from Atlas UI → Connect → Shell)
mongosh "mongodb+srv://myuser:mypassword@cluster0.abc123.mongodb.net/taskmanager"
# OR: Store connection string in environment variable (safer)
export MONGO_URI="mongodb+srv://myuser:mypassword@cluster0.abc123.mongodb.net"
mongosh $MONGO_URI
# Useful flag: disable telemetry
mongosh --nodb # start shell without connecting (for scripting)
# Run a script file
mongosh $MONGO_URI --file ./scripts/seed-data.js
# Run a one-liner
mongosh $MONGO_URI --eval "db.tasks.countDocuments({ status: 'pending' })"
Compass Workflow — Inspecting a Slow Query
Workflow: Diagnose and fix a slow API endpoint using Compass
1. IDENTIFY — Notice GET /api/v1/tasks is slow (>500ms response time)
2. REPRODUCE — Open Compass → Connect to dev database
Navigate to: taskmanager → tasks → Documents tab
Enter filter: { "userId": { "$oid": "64a1f..." }, "status": "pending" }
Click Explain
3. ANALYSE — Explain Plan shows:
Stage: COLLSCAN (full scan — no index used!)
Docs Examined: 50,000
Docs Returned: 15
Execution Time: 487ms
Ratio: 50,000:15 — terrible!
4. FIX — Navigate to: tasks → Indexes tab
Click "Create Index"
Add fields: userId (1 asc) + status (1 asc) + createdAt (-1 desc)
Index name: userId_status_createdAt
Click "Create Index"
5. VERIFY — Run Explain again
Stage: IXSCAN (index scan — using new index!)
Docs Examined: 15
Docs Returned: 15
Execution Time: 2ms
Ratio: 15:15 — perfect!
6. DEPLOY — Add index to Mongoose model:
taskSchema.index({ userId: 1, status: 1, createdAt: -1 });
7. CONFIRM — API endpoint now responds in <10ms
How It Works
Step 1 — mongosh Is a Full JavaScript REPL
mongosh is not just a MongoDB client — it is a complete JavaScript runtime. You can declare variables, write loops, define functions, and use modern JavaScript syntax (async/await, arrow functions, destructuring) directly in the shell. This makes it possible to write and execute complex migration scripts, data transformation jobs, and debugging scripts without a separate Node.js file.
Step 2 — Compass Visualises the Query Execution Plan
When MongoDB executes a query, it chooses an execution plan — a strategy for finding the matching documents. Compass renders this plan as a tree of stages. IXSCAN means MongoDB used an index to find documents efficiently. COLLSCAN means it scanned every document in the collection. The "Examined to Returned" ratio tells you how efficient the plan is — a ratio close to 1:1 means the index is narrow and precise.
Step 3 — The Schema Tab Reveals Data Quality Issues
Compass's Schema tab samples documents in a collection and analyses the types and distributions of every field. It shows what percentage of documents have each field, what data types appear (and flags inconsistencies), and histograms of value distributions for string, date, and numeric fields. This is invaluable when you inherit an existing database and need to understand its shape quickly.
Step 4 — The Aggregations Tab Enables Iterative Pipeline Building
Building aggregation pipelines in code — without seeing intermediate results — is error-prone. Compass's Aggregations tab lets you add stages one at a time and see the output of each stage before adding the next. When your pipeline is working correctly, Compass can export it as JavaScript code ready to paste into your Mongoose query.
Step 5 — Atlas Offers Compass-Level Insights in the Cloud UI
MongoDB Atlas includes a built-in Query Profiler that shows slow queries, their execution times, and performance advice directly in the web UI. The Atlas Performance Advisor automatically detects missing indexes based on actual query patterns and suggests which compound indexes to create. These tools make it possible to monitor and optimise a production MongoDB deployment without any additional monitoring infrastructure.
Common Mistakes
Mistake 1 — Running destructive commands without checking which database is active
❌ Wrong — dropped the wrong database:
// You think you're in taskmanager_test but you're in taskmanager
db.dropDatabase() // deleted production data!
// Always check: db → prints current database name
✅ Correct — always verify the current database before destructive operations:
db // prints: taskmanager — confirm this is the right one
db.getName() // same: 'taskmanager'
use taskmanager_test // switch to test database
db.tasks.drop() // now safe to drop
Mistake 2 — Using find() output directly without .toArray() in scripts
❌ Wrong — cursor object, not array, returned by find in scripts:
const tasks = db.tasks.find({ status: 'pending' });
tasks.length; // undefined — it's a cursor
JSON.stringify(tasks); // '[{}]' — cursor serialised as empty object
✅ Correct — convert cursor to array:
const tasks = db.tasks.find({ status: 'pending' }).toArray();
tasks.length; // 42 — actual count
Mistake 3 — Creating indexes in Compass without adding them to the Mongoose schema
❌ Wrong — index exists in Atlas but disappears on next test database reset:
Created index in Compass UI → works in production
Test database reset → index gone → tests run slow
New developer sets up local DB → index missing → performance issues
✅ Correct — define all indexes in the Mongoose schema as the source of truth:
// task.model.js — indexes defined in code, created automatically by Mongoose
taskSchema.index({ userId: 1, status: 1, createdAt: -1 });
taskSchema.index({ title: 'text', description: 'text' });
// Mongoose calls createIndex() on connection — idempotent, safe to repeat
Quick Reference — mongosh Commands
| Task | Command |
|---|---|
| Connect local | mongosh |
| Connect Atlas | mongosh "mongodb+srv://user:pass@cluster/db" |
| List databases | show dbs |
| Switch database | use taskmanager |
| Current database | db |
| List collections | show collections |
| Query collection | db.tasks.find({ status: 'pending' }) |
| Count documents | db.tasks.countDocuments({ status: 'pending' }) |
| Explain query | db.tasks.explain('executionStats').find(filter) |
| List indexes | db.tasks.getIndexes() |
| Create index | db.tasks.createIndex({ userId: 1, createdAt: -1 }) |
| Collection stats | db.tasks.stats() |
| Exit shell | exit |