MongoDB $nin Operator

Beginner
⏱️ 8 min read
📚 Updated: Jul 2026
🎯 4 Examples
Query Filter

What You’ll Learn

The $nin operator matches documents when a field’s value is not in a specified list. Use it in $match to exclude multiple statuses, categories, or IDs in one query instead of chaining many $ne conditions.

01

Exclusion List

Block multiple values.

02

Two Syntax Forms

Query filter vs expression.

03

$match Stage

Filter out unwanted rows.

04

Array Fields

Excludes on array elements.

05

Use Cases

Blocklists, cleanup.

06

$in Opposite

Inverse of membership.

Definition and Usage

In MongoDB, the $nin operator selects documents where a field’s value does not appear in a specified array. For example, { status: { $nin: [ "archived", "cancelled" ] } } returns every document whose status is neither "archived" nor "cancelled". It is the direct opposite of $in.

In aggregation expressions, { $nin: [ "$role", [ "guest", "banned" ] ] } returns true when the field value is not in the array. This is useful for access checks and conditional labeling.

💡
Beginner Tip

Think of $nin as “not in this list.” It is cleaner than writing { $and: [ { status: { $ne: "a" } }, { status: { $ne: "b" } } ] }. When you need to include values instead, use $in.

📝 Syntax

$nin has two forms depending on where you use it:

Query form (in $match or find filters)

mongosh
{ field: { $nin: [ <value1>, <value2>, ... ] } }

Aggregation expression form (in $project, $cond, etc.)

mongosh
{ $nin: [ <expression>, <array expression> ] }

Syntax Rules

  • Query form — keeps documents where the field does not equal any value in the array.
  • Expression form — returns true when the first operand is not found in the second array.
  • If the field is an array, a document is excluded when any element in the field array matches a listed value.
  • Values must match BSON types exactly (no automatic type conversion).
  • An empty $nin array { field: { $nin: [] } } matches all documents.
  • Query $nin also matches documents where the field is missing or null.

💡 $nin vs $in vs $ne

$in{ status: { $in: ["active", "pending"] } } (include listed values)
$nin{ status: { $nin: ["archived", "cancelled"] } } (exclude listed values)
$ne{ status: { $ne: "archived" } } (exclude one value only)

⚡ Quick Reference

QuestionAnswer
Operator typeQuery operator + aggregation expression
Query syntax{ field: { $nin: [ val1, val2 ] } }
Expression syntax{ $nin: [ expr, array ] }
Empty arrayMatches all documents
Missing fieldsQuery $nin includes documents without the field
$match filter
{
  status: {
    $nin: [ "archived", "cancelled" ]
  }
}

Exclude statuses

Expression
{
  $nin: [
    "$role",
    [ "guest", "banned" ]
  ]
}

Returns true/false

Exclude IDs
{
  userId: {
    $nin: [
      ObjectId("..."),
      ObjectId("...")
    ]
  }
}

Blocklist user IDs

With $exists
{
  status: {
    $exists: true,
    $nin: [ null, "" ]
  }
}

Field present, not empty

Examples Gallery

Exclude inactive statuses, filter in find(), add boolean access flags, and drive conditional logic with $nin.

📚 Exclude Multiple Statuses

Use an orders collection and hide archived and cancelled orders with $match.

Sample Input Documents

Suppose you have an orders collection with orderId, customer, and status:

mongosh
[
  { "_id": ObjectId("609c26812e9274a86871bc6a"), "orderId": "ORD-101", "customer": "Alice", "status": "active" },
  { "_id": ObjectId("609c26812e9274a86871bc6b"), "orderId": "ORD-102", "customer": "Bob",   "status": "archived" },
  { "_id": ObjectId("609c26812e9274a86871bc6c"), "orderId": "ORD-103", "customer": "Carol", "status": "pending" },
  { "_id": ObjectId("609c26812e9274a86871bc6d"), "orderId": "ORD-104", "customer": "Dave",  "status": "cancelled" }
]

Example 1 — $nin in a $match Stage

Find orders that are not archived or cancelled:

mongosh
db.orders.aggregate([
  {
    $match: {
      status: {
        $nin: [ "archived", "cancelled" ]
      }
    }
  }
])

How It Works

  • Alice (active) and Carol (pending) pass the filter.
  • Bob (archived) and Dave (cancelled) are excluded.
  • One $nin replaces two separate $ne conditions.

📈 Practical Patterns

Use find(), exclude categories, add boolean flags, and build access rules.

Example 2 — $nin in a find() Query

Exclude products in unwanted categories outside an aggregation pipeline:

mongosh
db.products.find({
  category: {
    $nin: [ "discontinued", "internal" ]
  }
})

How It Works

$nin in find() uses the same query form as $match. It is ideal for storefront catalogs that hide internal or retired product categories.

Example 3 — Add a Boolean Field with $project

Flag users whose role is not in an allowed list:

mongosh
db.users.aggregate([
  {
    $project: {
      name: 1,
      role: 1,
      hasAccess: {
        $nin: [
          "$role",
          [ "guest", "banned" ]
        ]
      }
    }
  }
])

How It Works

Expression $nin returns true when the role is not in the blocklist. Note: here true means “has access” because the role is outside the denied list.

Example 4 — $nin Inside $cond

Label products as “visible” or “hidden” based on category blocklist:

mongosh
db.products.aggregate([
  {
    $project: {
      name: 1,
      category: 1,
      visibility: {
        $cond: [
          {
            $nin: [
              "$category",
              [ "discontinued", "internal" ]
            ]
          },
          "visible",
          "hidden"
        ]
      }
    }
  }
])

How It Works

When $nin returns true (category not in the blocklist), $cond outputs "visible". Otherwise it outputs "hidden".

Bonus — $nin with Array Fields (tags)

Exclude articles tagged with blocked keywords:

mongosh
db.articles.find({
  tags: {
    $nin: [ "spam", "draft" ]
  }
})

// tags: ["mongodb", "tutorial"]     → included
// tags: ["mongodb", "draft"]         → excluded (draft in tags)
// tags: ["spam"]                     → excluded

How It Works

When the field is an array, $nin excludes the document if any tag matches a value in the exclusion list. This is the array-field counterpart to single-value exclusion.

🚀 Use Cases

  • Status blocklists — hide archived, cancelled, or deleted records from active views.
  • Category filtering — exclude discontinued or internal products from public catalogs.
  • Access control — flag users whose roles are not in an allowed set (or are in a denied set).
  • Content moderation — filter out documents tagged with blocked keywords.

🧠 How $nin Works

1

MongoDB reads the field and list

In $match, it checks a field against an exclusion array. In expressions, it evaluates a value and an array operand.

Input
2

$nin checks membership

MongoDB tests whether the field value appears in the array. If it does, the document is excluded (query) or false is returned (expression).

Compare
3

Non-matching documents pass

In $match, documents outside the blocklist continue. In expressions, true means “not in the list.”

Output
=

Clean exclusion filters

You get documents or boolean flags with unwanted values filtered out efficiently.

Conclusion

The $nin operator is the standard way to exclude multiple values in MongoDB queries. It is the inverse of $in and more concise than chaining multiple $ne conditions.

Remember that an empty $nin array matches everything, query form includes missing fields, and expression form returns a boolean. Next in the series: $nor.

💡 Best Practices

✅ Do

  • Use $nin when excluding two or more values from one field
  • Pair with $exists: true when missing fields should not match
  • Use expression $nin inside $cond for blocklist logic
  • Keep BSON types consistent in the exclusion array
  • Prefer $in for allowlists and $nin for blocklists

❌ Don’t

  • Use $nin with an empty array expecting no matches (it matches all)
  • Forget that query $nin includes documents without the field
  • Chain many $ne conditions when one $nin suffices
  • Confuse query syntax with expression syntax
  • Mix string and number types in the exclusion list

Key Takeaways

Knowledge Unlocked

Five things to remember about $nin

Use these points when building exclusion filters in MongoDB.

5
Core concepts
📝 02

Two Forms

Query vs expression.

Syntax
🔄 03

Inverse of $in

Block vs allow.

Related
04

Empty Array

Matches everything.

Edge case
📑 05

Array Fields

Any element counts.

Arrays

❓ Frequently Asked Questions

$nin matches documents where a field does not equal any value in a given array. In query filters it excludes listed values. In aggregation expressions it returns true when the first value is not found in the second array.
Query form: { field: { $nin: [ value1, value2, ... ] } }. Aggregation expression form: { $nin: [ <expression>, <array expression> ] }. The query form filters documents; the expression form returns true or false.
$ne excludes a single value: { status: { $ne: "archived" } }. $nin excludes any value in an array: { status: { $nin: ["archived", "cancelled"] } }. Use $nin when you need to exclude multiple values at once.
Yes. Like $ne, query $nin also matches documents that do not contain the field or where the field is null. Combine with $exists: true if you only want documents with the field present.
An empty array { field: { $nin: [] } } matches all documents, because no excluded values exist. This is the opposite of $in, where an empty array matches nothing.

Continue the Operator Series

Move on to $nor for logical NOR conditions, or review $in for the allowlist counterpart.

Next: $nor →

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