MongoDB $nin Operator

Beginner
5 min read
Updated: Oct 2026
3 examples
Live preview

What Is $nin?

$nin means not in. It keeps documents where a field’s value is not equal to any value in a list—or where the field is missing. Think of it as excluding several bad statuses in one filter.

Remember
$nin = not in this list

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

{ status: { $nin: ["archived", "cancelled"] } }
  → keep open, pending, ...
  → drop archived, cancelled
  → also keep docs missing status

$nin: [] → matches everything
use in find() or $match
UsePrefer
Exclude several values$nin
Exclude one value$ne
Keep listed values$in

How to Use $nin in MongoDB

List the values to exclude, then filter with find() or $match.

  1. Choose the field to test (for example status).
  2. Build an array of values to exclude.
  3. Write { field: { $nin: [ ... ] } } in find() or $match.
  4. Add $exists: true if missing fields should not match.
PieceRequired?Role
FieldYesValue to test
$nin arrayYesValues to exclude
$existsNoRequire the field to be present

Pseudocode

Pseudocode
excluded = [value1, value2, ...]

for each document:
    if field is missing:
        keep document          // default $nin behavior
    else if field value is in excluded:
        drop document
    else:
        keep document

Cheat Sheet

Keep these facts handy while writing exclusion filters.

TopicDetail
TypeQuery / $match predicate
Syntax{ field: { $nin: [ ... ] } }
MeaningField not equal to any listed value
Missing fieldMatches by default
Empty list$nin: [] matches all docs
Array fieldKeeps docs with no array element in the list
Opposite$in

Live Preview

Exclude ["archived", "cancelled"]. Pick a status and see if the document is kept.

Simulates { status: { $nin: ["archived", "cancelled"] } } (same idea as the mongosh examples below).

Result
status = "open"
$nin ["archived", "cancelled"] → KEEP

{ status: "open" }  // matches

Worked Walkthrough — Active Orders

Drop orders that are archived or cancelled. Keep everything else.

Calculation
Exclude list = ["archived", "cancelled"]

status "open"      → not in list → KEEP
status "pending"   → not in list → KEEP
status "archived"  → in list     → DROP
status "cancelled" → in list     → DROP

Filter:
  { status: { $nin: ["archived", "cancelled"] } }

MongoDB Examples

We use a small orders collection. First we exclude two statuses, then show how array fields work with $nin. Run these in mongosh after inserting the sample data once.

Example 1 — Sample Data

Imagine four orders with different statuses. We save them in a collection named orders.

mongosh
db.orders.insertMany([
  { _id: 1, item: "pens",  status: "open" },
  { _id: 2, item: "pads",  status: "archived" },
  { _id: 3, item: "clips", status: "pending" },
  { _id: 4, item: "tape",  status: "cancelled" }
]);

How the Data Is Stored in MongoDB

After the insert, MongoDB keeps four documents. Run find() to see them:

mongosh
db.orders.find()

Read one document like this:

Field in MongoDBValue (doc 1)Plain English
item"pens"Product name
status"open"Order state

How It Works

  1. Insert once. insertMany adds four order documents.
  2. status is a string. We will exclude some statuses next.
  3. find() shows the same shape. Ready for $nin.

Example 2 — Exclude Statuses

Goal: keep orders that are not archived and not cancelled.

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

// same idea in aggregation:
// db.orders.aggregate([
//   { $match: { status: { $nin: ["archived", "cancelled"] } } }
// ]);

How It Works

  1. Build the exclude list. ["archived", "cancelled"] are the statuses to drop.
  2. $nin tests membership. open and pending are not in the list → kept.
  3. Dropped rows. archived and cancelled match the list → removed.
  4. One condition. Better than writing two separate $ne checks.

Example 3 — Array Field

When the field is an array, $nin keeps documents where none of the array elements equal a listed value.

mongosh
db.movies.insertMany([
  { _id: 1, title: "Baseball", genres: ["Documentary", "History", "Sport"] },
  { _id: 2, title: "Centennial", genres: ["Action", "Adventure", "Drama"] }
]);

db.movies.find({
  genres: { $nin: ["Drama"] }
});

How It Works

  1. Array field. genres holds several strings per movie.
  2. No matching element. Baseball has no "Drama" → kept.
  3. Has matching element. Centennial includes "Drama" → dropped.
  4. Missing field. A movie without genres would also match $nin by default.

Edge Cases & Pitfalls

Check these before using $nin in production queries.

missing

Missing fields match

$nin keeps documents without the field. Add $exists: true when that is unwanted.

empty

Empty array matches everything

{ field: { $nin: [] } } excludes nothing, so every document matches. Double-check dynamic lists before they go empty.

selectivity

$nin is often not selective

Excluding a few values can still match most of a collection. Pair with other selective filters when you can.

vs

One value → prefer $ne

For a single exclusion, $ne is clearer. Reserve $nin for two or more values.

Performance Notes

ApproachCostBest for
$nin aloneOften broad match setExclude a short list
$nin + other filtersUsually betterNarrow then exclude
Positive $in listOften more selectiveWhen allowed values are few

Like $ne, $nin can match a large share of an index. Prefer a positive $in of allowed values when that list is smaller, and combine with selective $match conditions.

Key Takeaways

  • Role: exclude any value in a list.
  • Syntax: { field: { $nin: [ ... ] } }.
  • Missing fields usually match.
  • Opposite of $in.

One line: $nin answers “is this value outside my exclude list?”—and keeps those documents.

Frequently Asked Questions

$nin (not in) selects documents where a field’s value is not equal to any value in a given array—or where the field does not exist. Use it in find() and $match to exclude several values at once.
The syntax is { field: { $nin: [ <value1>, <value2>, ... ] } }. Pass an array of values to exclude. There is no separate aggregation $nin expression—use this form in $match, or combine $not with $in for a boolean in expressions.
$ne excludes one value. $nin excludes any value in a list. Prefer $nin when you need to skip several statuses or codes in one condition.
$in keeps documents whose field matches any listed value. $nin keeps documents whose field matches none of the listed values (and usually missing fields).
Yes. Query $nin matches documents that do not contain the field. Combine with $exists: true if you only want documents where the field is present.
{ field: { $nin: [] } } matches all documents, because there are no values to exclude. That is the opposite of $in with an empty array, which matches nothing.

Next: $nor

Match documents that fail every condition in a list.

$nor tutorial →

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.

9 people found this page helpful