The MongoDB Shell — mongosh Commands and the MongoDB Compass GUI

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
Note: 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)).
Tip: Use Compass’s Explain Plan feature before adding any new index. Run your query in the Documents tab, click “Explain”, and check the 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.
Warning: Never run 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

🧠 Test Yourself

Compass's Explain Plan shows COLLSCAN for a query filtering by userId and status. What does this mean and what should you do?