MongoDB $currentOp Stage

Beginner
⏱️ 11 min read
📚 Updated: Jul 2026
🎯 5 Examples
Aggregation

What You’ll Learn

The $currentOp stage streams live operation documents from the server—running queries, writes, aggregations, idle cursors, and transaction sessions—so DBAs can diagnose slowness and connection load.

01

Live ops feed

One doc per operation.

02

admin database

Required run context.

03

First stage

Then $match filter.

04

secs_running

Spot slow queries.

05

allUsers

See every client op.

06

opid + killOp

Terminate if needed.

Definition and Usage

$currentOp is an aggregation stage that reports what MongoDB is doing right now. Unlike stages that read collection data, it reads internal server state and outputs diagnostic documents you can filter with normal pipeline stages.

💡
Beginner tip

Run on admin, not on your app database: db.getSiblingDB("admin").aggregate([{ $currentOp: {} }]). MongoDB recommends $currentOp over the deprecated db.currentOp() method because you can add $match, $project, and $sort afterward.

Use $currentOp to find long-running queries, inspect who holds connections to a collection, detect idle transaction sessions, and gather opid values before calling db.killOp().

📝 Syntax

$currentOp takes an options object (all fields optional):

mongosh
db.getSiblingDB("admin").aggregate([
  {
    $currentOp: {
      allUsers: <boolean>,
      idleConnections: <boolean>,
      idleCursors: <boolean>,
      idleSessions: <boolean>,
      localOps: <boolean>,
      targetAllNodes: <boolean>
    }
  }
])

Syntax Rules

  • First stage$currentOp must be stage 1 in the pipeline.
  • admin only — pipelines starting with $currentOp run on the admin database.
  • allUsers — default false (your ops only); set true for cluster-wide view (needs inprog privilege).
  • idleSessions — default true; includes inactive transaction sessions holding locks.
  • Downstream stages$match, $project, $group work on the operation stream.
  • No transactions$currentOp cannot run inside a multi-document transaction.
mongosh
db.getSiblingDB("admin").aggregate([
  { $currentOp: {} },
  { $match: { active: true } },
  { $limit: 10 }
])

⚡ Quick Reference

QuestionAnswer
Run onadmin database only
Stage positionMust be first
OutputOne document per operation / session / cursor
Slow query fieldsecs_running (active ops only)
Namespacensdatabase.collection
Kill operationdb.killOp(document.opid)
All active ops
{ $currentOp: {
  allUsers: true
}}
{ $match: { active: true }}

Cluster view

Slow queries
secs_running: {
  $gte: 10
}

10+ seconds

By collection
ns: "mydb.orders"

$match filter

Idle sessions
{ $match: {
  type: "idleSession"
}}

Transactions

🧰 Parameters

Options inside the $currentOp object control what appears in the stream:

allUsers Optional

false (default): only your user’s operations. true: all users—requires inprog role on secured deployments.

allUsers: true
idleConnections Optional

false (default): active ops only. true: include idle open connections.

idleConnections: true
idleCursors Optional

true: report open cursors not currently in getMore. Type becomes idleCursor.

idleCursors: true
idleSessions Optional

Default true. Includes inactive transaction sessions (type: idleSession) holding locks.

idleSessions: true

Examples Gallery

Admin-database pipelines—list active operations, find slow queries, filter by collection, summarize connections, and inspect idle transaction sessions.

📚 Getting Started

Open the operation stream and list what is active now.

Example 1 — List active operations

mongosh
db.getSiblingDB("admin").aggregate([
  { $currentOp: { allUsers: true } },
  { $match: { active: true } },
  {
    $project: {
      _id: 0,
      op: 1,
      ns: 1,
      secs_running: 1,
      client: 1,
      desc: 1
    }
  },
  { $limit: 20 }
])

/* Sample row:
{
  op: "query",
  ns: "shop.orders",
  secs_running: 2,
  client: "198.51.100.1:50428",
  desc: "Conn"
} */

How It Works

Each document in the cursor is one server-side operation. active: true means it is running right now; ns shows which collection is involved.

📈 Practical Patterns

Slow queries, namespace filters, connection counts, and transactions.

Example 2 — Find queries running longer than 5 seconds

mongosh
db.getSiblingDB("admin").aggregate([
  { $currentOp: { allUsers: true } },
  {
    $match: {
      active: true,
      secs_running: { $gte: 5 },
      op: { $in: ["query", "command", "getmore"] }
    }
  },
  {
    $project: {
      op: 1,
      ns: 1,
      secs_running: 1,
      opid: 1,
      "command.filter": 1,
      "command.aggregate": 1
    }
  },
  { $sort: { secs_running: -1 } }
])

// To terminate (use with extreme caution):
// db.killOp(<opid from result>)

How It Works

secs_running exists only when active is true. Sort descending to see the worst offenders first. Save opid if you must call killOp after confirming the query is safe to stop.

Example 3 — Operations on a specific collection

mongosh
db.getSiblingDB("admin").aggregate([
  { $currentOp: { allUsers: true } },
  {
    $match: {
      ns: "shop.orders",
      active: true
    }
  },
  {
    $project: {
      op: 1,
      secs_running: 1,
      client: 1,
      effectiveUsers: 1,
      command: 1
    }
  }
])

/* Shows every active op touching shop.orders —
   useful when one collection suddenly spikes CPU. */

How It Works

Filter ns to zoom in on one hot collection. Combine with effectiveUsers to see which database user initiated the work.

Example 4 — Count connections per client and namespace

mongosh
db.getSiblingDB("admin").aggregate([
  {
    $currentOp: {
      allUsers: true,
      idleConnections: true,
      idleSessions: true
    }
  },
  {
    $project: {
      _id: 0,
      client: { $arrayElemAt: [{ $split: ["$client", ":"] }, 0] },
      curr_active: { $cond: [{ $eq: ["$active", true] }, 1, 0] },
      curr_inactive: { $cond: [{ $eq: ["$active", false] }, 1, 0] },
      user: "$effectiveUsers.user",
      ns: "$ns"
    }
  },
  { $match: { client: { $ne: null }, user: { $ne: null } } },
  {
    $group: {
      _id: { client: "$client", user: "$user", ns: "$ns" },
      active: { $sum: "$curr_active" },
      inactive: { $sum: "$curr_inactive" },
      total: { $sum: 1 }
    }
  },
  { $sort: { total: -1 } },
  { $limit: 10 }
])

/* Result shape:
{ _id: { client: "10.0.0.5", user: ["appUser"], ns: "shop.orders" },
  active: 3, inactive: 1, total: 4 } */

How It Works

Enable idleConnections to include open but idle sockets. Group by client IP and namespace to spot connection pool leaks or runaway services.

Example 5 — Inactive transaction sessions

mongosh
db.getSiblingDB("admin").aggregate([
  { $currentOp: { allUsers: true, idleSessions: true } },
  { $match: { type: "idleSession" } },
  {
    $project: {
      type: 1,
      client: 1,
      lsid: 1,
      "transaction.parameters.txnNumber": 1,
      "transaction.timeOpenMicros": 1,
      waitingForLock: 1,
      active: 1
    }
  }
])

// Equivalent filter:
// { $match: { active: false, transaction: { $exists: true } } }

// On mongos sharded clusters, add localOps: true for a
// composite transaction view instead of per-shard docs.

How It Works

Idle sessions are transactions waiting on the client—not actively executing but still holding locks. Long timeOpenMicros values often mean an app forgot to commit or abort.

🧠 How $currentOp Works

1

Admin aggregate starts

Client runs admin.aggregate([{ $currentOp: options }]) with optional flags.

Connect
2

Server collects ops

MongoDB gathers active ops, idle connections/cursors/sessions per your options.

Collect
3

Pipeline filters

$match, $project, $group shape the diagnostic stream like normal data.

Filter
=

Actionable ops list

DBA sees slow queries, hot namespaces, or stale transactions—and can act.

📝 Notes

  • Run on admin—pipelines starting with $currentOp fail on other databases.
  • allUsers: true needs the inprog privilege when access control is enabled.
  • secs_running appears only when active: true—idle sessions use transaction timing fields instead.
  • On sharded clusters, add localOps: true on mongos for a unified transaction view.
  • targetAllNodes: true returns one doc per data-bearing node (not just per shard).
  • Previous topic: $count. Next: $facet.

Conclusion

$currentOp is MongoDB’s pipeline-native way to see what the server is doing right now. Start on admin, enable allUsers for ops visibility, filter with $match, and use secs_running to catch slow queries early.

Treat killOp as a last resort after identifying client-owned operations. Next in the series: $facet for parallel sub-pipelines.

💡 Best Practices

✅ Do

  • Always use db.getSiblingDB("admin") for $currentOp pipelines
  • Add $project to trim noisy fields before returning to dashboards
  • Sort by secs_running descending when hunting slow queries
  • Check idle transaction sessions when locks block unrelated writes
  • Grant inprog only to trusted admin roles

❌ Don’t

  • Run $currentOp on application databases—it must be admin
  • Call killOp on operations you have not verified
  • Assume db.currentOp() is the modern approach—it is deprecated
  • Use inside multi-document transactions
  • Poll $currentOp in tight loops in production—rate-limit monitoring queries

Key Takeaways

Knowledge Unlocked

Five things to remember about $currentOp

Use these points when monitoring MongoDB operations.

5
Core concepts
🔒 02

admin DB

Required context.

Setup
⏱️ 03

secs_running

Slow query hunt.

Perf
👥 04

allUsers

Full cluster view.

Option
🚫 05

opid

killOp carefully.

Action

❓ Frequently Asked Questions

$currentOp returns a stream of documents describing in-progress and dormant operations—queries, writes, aggregations, idle cursors, and inactive transaction sessions. Each document represents one operation or session. It replaces the deprecated db.currentOp() helper.
Always run the pipeline on the admin database: db.getSiblingDB("admin").aggregate([{ $currentOp: {} }, …]). $currentOp must be the first stage and cannot start on a regular user database.
allUsers (see all users' ops), idleConnections, idleCursors, idleSessions (default true), localOps (mongos-only), and targetAllNodes (sharded). An empty object { $currentOp: {} } uses all defaults.
Chain $match after $currentOp: { active: true, secs_running: { $gte: 5 }, op: { $in: ["query", "command", "getmore"] } }. secs_running appears only on active operations.
Yes. Active operation documents include opid. Pass it to db.killOp(opid) in mongosh—but only terminate client-initiated ops you understand; killing internal server operations can destabilize the node.
On deployments with access control enabled, the inprog privilege is required on sharded clusters. On standalone/replica sets, inprog is required when allUsers: true. Without it you may only see your own operations.
Did you know?

MongoDB deprecated the currentOp command and db.currentOp() in favor of $currentOp because the aggregation form supports $match, $group, and $sort—turning raw ops dumps into focused admin reports. See the official $currentOp docs.

Continue the Stages Series

Monitor live operations with $currentOp, then run parallel pipelines with $facet.

Next: $facet →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful