$cmp is a MongoDB aggregation expression that compares two values and returns a three-way result: -1 (less), 0 (equal), or 1 (greater). It uses BSON comparison order when types differ.
Remember
$cmp = three-way compare for aggregation
{ $cmp: [ <a>, <b> ] }
a < b → -1
a = b → 0
a > b → 1
$cmp([200, 250]) → -1
$cmp([250, 250]) → 0
$cmp([300, 250]) → 1
true/false checks → prefer $lt / $eq / $gt
Build { $cmp: [ left, right ] } with fields or literals.
Read -1, 0, or 1 as “less”, “equal”, or “greater”.
Optionally map that result with $switch into labels.
Piece
Required?
Role
$cmp
Yes
Three-way compare → -1 / 0 / 1
Two expressions
Yes
Left and right values to compare
$switch
No
Turn the code into below / exact / above labels
Pseudocode
Pseudocode
for each document:
a = evaluate(expression1)
b = evaluate(expression2)
// missing fields behave like null
if a < b (BSON order):
result = -1
else if a > b (BSON order):
result = 1
else:
result = 0
emit { ..., field: result }
Reference
Cheat Sheet
Keep these facts handy while writing comparison expressions.
Topic
Detail
Type
Aggregation expression (not a find filter)
Syntax
{ $cmp: [ <a>, <b> ] }
Returns
-1, 0, or 1
Order
BSON type + value comparison order
Missing field
Treated like null
Sample check
$cmp(["$qty", 250]) vs stock threshold
Boolean siblings
$lt, $eq, $gt
Try it
Live Preview
Watch $cmp return -1, 0, or 1 for a quantity versus the target 250.
Simulates { $cmp: ["$qty", 250] } (same idea as the mongosh examples below).
Same threshold for every item. The only question is whether qty is below, equal to, or above 250.
Calculation
Target = 250
qty 200: 200 < 250 → $cmp → -1 (below)
qty 250: 250 = 250 → $cmp → 0 (exact)
qty 300: 300 > 250 → $cmp → 1 (above)
Remember the order of arguments:
$cmp([ "$qty", 250 ]) // qty first, target second
not the other way around
Code
MongoDB Examples
We store three inventory items, compare each qty to 250, then label the result with $switch. Run these in mongosh after inserting the sample data once.
Example 1 — Sample Data
Imagine a tiny inventory collection with three products. One is below 250, one matches, and one is above.
Check these before using $cmp in production pipelines.
order
Argument order flips the sign
$cmp([a, b]) is not the same as $cmp([b, a]). Keep “value first, threshold second” consistent.
types
Different types still compare
$cmp uses BSON order across types. A string and a number are comparable, but the result may surprise you—normalize types when needed.
null
Missing fields act like null
A missing qty compared with 250 returns -1 (null < number), not an error. Filter or default first if that is wrong for your app.
boolean
Need true/false? Use $lt / $eq / $gt
Do not force $cmp into boolean logic. Prefer $lt, $eq, or $gt for simple predicates.
Analysis
Performance Notes
Approach
Cost
Best for
$cmp alone
Per-document compare
Three-way codes in reports
$cmp + $switch
Still O(docs)
Human-readable below/exact/above labels
$gt / $lt instead
Similar cost, boolean result
Simple true/false filters
Comparison expressions are cheap compared with large sorts or joins. Filter early with $match when only some documents need a compare.
Remember
Key Takeaways
Role: three-way compare → -1 / 0 / 1.
Syntax:{ $cmp: [a, b] }.
Labels: pair with $switch for below/exact/above.
Booleans: prefer $lt / $eq / $gt when you only need true/false.
One line:$cmp answers “is the left value less, equal, or greater?”—as -1, 0, or 1.
Frequently Asked Questions
$cmp compares two values and returns -1 if the first is less, 0 if they are equal, or 1 if the first is greater. Use it inside aggregation expression stages such as $project and $addFields.
The syntax is { $cmp: [ <expression1>, <expression2> ] }. Both sides can be fields, literals, or nested expressions.
Use $gt, $lt, $eq, and friends for true/false checks. Use $cmp when you need a three-way result (-1, 0, 1) for branching with $switch or custom comparison logic.
Yes. $cmp compares value and type using MongoDB’s BSON comparison order. For example, null sorts before numbers, so $cmp([null, 5]) returns -1.
A missing field is treated like null for comparison. $cmp(["$missing", 250]) returns -1 because null is less than a number.
Yes in spirit. Think of it as aggregation’s three-way compare: less → -1, equal → 0, greater → 1.