MongoDB $setDifference Operator

Beginner
⏱️ 8 min read
📚 Updated: Jul 2026
🎯 4 Examples
Set / Array

What You’ll Learn

The $setDifference operator returns elements that are in the first array but not in any of the others. Think of it as set subtraction: A − B gives you what is in A alone.

01

A minus B

Set subtraction.

02

Array Syntax

Two+ arrays.

03

Set Semantics

Unique values.

04

Aggregation

$project / $addFields.

05

Use Cases

Tags, permissions.

06

Set Family

Union, intersection.

Definition and Usage

In MongoDB’s aggregation framework, the $setDifference operator compares two or more arrays as sets and returns elements present in the first array but absent from all subsequent arrays. For example, { $setDifference: [ [1, 2, 3], [3, 4] ] } returns [1, 2].

Set operators ignore duplicate values and compare elements for equality. Use $setDifference when you need “what does this list have that the other list does not?” — such as tags a user follows minus blocked tags, or wishlist items not yet in the cart.

💡
Beginner Tip

Order matters: the first array is the minuend (what you start with). The second and later arrays are subtracted from it. Swap the arrays and you get a different result.

📝 Syntax

The $setDifference operator takes an array of two or more array expressions:

mongosh
{ $setDifference: [ <array1>, <array2>, ... ] }

Literal Example

mongosh
{ $setDifference: [ [1, 2, 3], [3, 4] ] }
// Result: [1, 2]

{ $setDifference: [ ["a", "b", "c"], ["b"], ["c", "d"] ] }
// Result: ["a"]

Syntax Rules

  • First array — the source set; elements here are candidates for the result.
  • Other arrays — values to exclude from the result (combined as a set).
  • Set semantics — duplicates in input arrays are ignored; each value appears once in output.
  • Equality — uses MongoDB’s comparison rules (same as $setIntersection).
  • Returns null if any input array is null.
  • Use inside $project, $addFields, or $set.

💡 $setDifference vs $setIntersection vs $setUnion vs $setEquals

A = [1,2,3], B = [2,3,4]
$setDifference [A, B] → [1] (in A only)
$setIntersection [A, B] → [2, 3] (in both)
$setUnion [A, B] → [1, 2, 3, 4] (all unique)
$setEquals [A, B] → false (same set?)

⚡ Quick Reference

QuestionAnswer
Operator typeAggregation expression operator (set / array)
Syntax{ $setDifference: [ arr1, arr2, ... ] }
Minimum arraysTwo
OutputArray of elements in first set minus others
Common stages$project, $addFields, $set
Literals
{
  $setDifference: [
    [1, 2, 3],
    [3, 4]
  ]
}

→ [1, 2]

Fields
{
  $setDifference: [
    "$tags",
    "$blocked"
  ]
}

Tag diff

Three arrays
[
  "$all",
  "$a",
  "$b"
]

Minus A and B

Empty result
[ ]

All excluded

Examples Gallery

Find tags a user keeps but has blocked, wishlist items not in the cart, skills gaps, and subtract multiple exclusion lists with $setDifference.

📚 User Tag Preferences

Find tags a user follows that are not in their blocked list.

Sample Input Documents

Suppose you have a users collection:

mongosh
[
  {
    "_id": 1,
    "name": "Alice",
    "tags": ["mongodb", "nodejs", "database"],
    "blockedTags": ["spam", "database"]
  },
  {
    "_id": 2,
    "name": "Bob",
    "tags": ["python", "ml"],
    "blockedTags": ["python"]
  },
  {
    "_id": 3,
    "name": "Carol",
    "tags": ["mongodb", "mongodb", "tutorial"],
    "blockedTags": []
  }
]

Example 1 — Tags Not Blocked

Compute allowed tags as tags minus blockedTags:

mongosh
db.users.aggregate([
  {
    $project: {
      name: 1,
      tags: 1,
      blockedTags: 1,
      allowedTags: {
        $setDifference: [
          "$tags",
          "$blockedTags"
        ]
      }
    }
  }
])

How It Works

Elements in tags that also appear in blockedTags are excluded. Set semantics deduplicate mongodb for Carol.

📈 E-Commerce and Skills

Wishlist gaps, skill comparisons, and counting remaining items.

Example 2 — Wishlist Items Not in Cart

Find product IDs still on the wishlist but not yet purchased:

mongosh
db.customers.aggregate([
  {
    $project: {
      name: 1,
      stillWanted: {
        $setDifference: [
          "$wishlist",
          "$cart"
        ]
      }
    }
  }
])

// wishlist: ["P100", "P200", "P300"]
// cart:     ["P200"]
// stillWanted: ["P100", "P300"]

How It Works

The first array is the wishlist; the second is subtracted. Items in both lists disappear from the result.

Example 3 — Required Skills Not Yet Held

Compare a job’s required skills against a candidate’s skills:

mongosh
db.jobs.aggregate([
  {
    $lookup: {
      from: "candidates",
      localField: "candidateId",
      foreignField: "_id",
      as: "candidate"
    }
  },
  { $unwind: "$candidate" },
  {
    $project: {
      title: 1,
      missingSkills: {
        $setDifference: [
          "$requiredSkills",
          "$candidate.skills"
        ]
      }
    }
  }
])

// required: ["mongo", "node", "react"]
// candidate skills: ["mongo", "node"]
// missingSkills: ["react"]

How It Works

Put the “required” list first and subtract what the candidate already has. The result is the skill gap.

Example 4 — Count Remaining Tags

Use $size on the difference result:

mongosh
db.users.aggregate([
  {
    $project: {
      name: 1,
      allowedCount: {
        $size: {
          $setDifference: [
            "$tags",
            "$blockedTags"
          ]
        }
      }
    }
  }
])

How It Works

$size counts how many unique allowed tags remain after subtraction. Handy for dashboards and validation rules.

Bonus — Subtract Multiple Exclusion Lists

Remove elements found in either of two block lists:

mongosh
db.users.aggregate([
  {
    $project: {
      name: 1,
      visibleTags: {
        $setDifference: [
          "$tags",
          "$blockedTags",
          "$systemHiddenTags"
        ]
      }
    }
  }
])

// tags minus (blockedTags ∪ systemHiddenTags)

How It Works

Pass more than two arrays. The first array minus the union of all others — one operator instead of chaining multiple steps.

🚀 Use Cases

  • Tag and category filtering — show content tags minus user-blocked or hidden tags.
  • Shopping workflows — wishlist items not yet in cart or order history.
  • Permissions — granted roles minus revoked roles.
  • Gap analysis — required skills, features, or IDs minus what is already present.

🧠 How $setDifference Works

1

MongoDB evaluates each array

All arguments resolve to arrays (field paths, literals, or nested expressions).

Input
2

Later arrays form the exclusion set

The second and subsequent arrays are combined; any matching value is excluded.

Exclude
3

First-array survivors are collected

Each unique element from the first array not in the exclusion set is added to the result.

Collect
=

Difference array

Elements in set A but not in B (or B ∪ C ∪ …).

Conclusion

The $setDifference operator subtracts one or more arrays from the first array using set semantics. It answers “what is in A but not in B?” inside aggregation pipelines without application-side set logic.

Remember: first array is the source, duplicates are deduplicated, and order follows the first array’s survivors. Next in the series: $setEquals.

💡 Best Practices

✅ Do

  • Put the “source” array first and exclusion arrays after
  • Use $ifNull for missing arrays (e.g. treat null as [])
  • Pair with $size to count remaining elements
  • Use $setIntersection when you need shared elements instead
  • Normalize string casing before comparing tag-like values if needed

❌ Don’t

  • Expect duplicate preservation from the first array
  • Swap array order casually — [B, A][A, B]
  • Use $setDifference when you need ordered list diff (use $filter)
  • Forget that null input arrays return null
  • Confuse set difference with numeric subtraction

Key Takeaways

Knowledge Unlocked

Five things to remember about $setDifference

Use these points when comparing arrays as sets in pipelines.

5
Core concepts
📝 02

[ arr1, arr2 ]

Two or more arrays.

Syntax
🛠 03

Unique only

Set semantics.

Output
🗃 04

Order matters

First = source.

Rule
05

null in

null out.

Edge case

❓ Frequently Asked Questions

$setDifference returns elements that appear in the first array but not in any of the subsequent arrays. It treats arrays as sets, so duplicate values are ignored and order follows the first array's remaining elements.
The syntax is { $setDifference: [ <array1>, <array2>, ... ] }. Each argument is an array expression (field path or literal). The result is array1 minus the union of all other arrays.
No. $setDifference uses set semantics. Each value appears at most once in the result, even if it appeared multiple times in the first array.
$setDifference compares two or more arrays as sets and returns values in the first array missing from the others. $filter walks one array and keeps elements that pass a condition — better for custom logic on a single array.
$setDifference returns A minus B (elements only in A). $setIntersection returns elements in all arrays. $setUnion returns all unique elements from every array combined.

Continue the Operator Series

Move on to $setEquals to test whether two arrays represent the same set, or review $filter for single-array conditions.

Next: $setEquals →

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