In MongoDB, you can use the $subtract aggregation pipeline operator to subtract numbers and/or dates.
Specifically, $subtract can do the following three things:
- Subtract two numbers to return the difference
- Subtract a number (in milliseconds) from a date and return the resulting date
- Subtract two dates to return the difference in milliseconds
The $subtract operator accepts the values as arguments. The arguments can be any valid expression as long as they resolve to numbers and/or dates. To subtract a number from a date, the date must be the first argument..
Sample Data
Suppose we have a collection called data with the following document:
{
"_id" : 1,
"a" : 20000,
"b" : 250,
"start" : ISODate("2021-01-03T00:00:00Z"),
"end" : ISODate("2021-01-03T23:30:15.100Z")
}
Subtract Numbers
We can use the $subtract operator to subtract the a field from the b field (or vice-versa).
Example:
db.data.aggregate(
[
{ $project: {
_id: 0,
a: 1,
b: 1,
result: {
$subtract: [ "$a", "$b" ] } }
}
]
)
Result:
{ "a" : 20000, "b" : 250, "result" : 19750 }
Subtract a Number from a Date
If the first argument is a date and the second argument is a number, the $subtract operator subtracts the number from the date in milliseconds.
Example:
db.data.aggregate(
[
{ $project: {
_id: 0,
b: 1,
start: 1,
result: {
$subtract: [ "$start", "$b" ] } }
}
]
).pretty()
Result:
{
"b" : 250,
"start" : ISODate("2021-01-03T00:00:00Z"),
"result" : ISODate("2021-01-02T23:59:59.750Z")
}
We can see that 250 milliseconds has been subtracted from the date.
When we subtract a number from a date, the date must be the first argument with the number as the second argument.
Here’s what happens if we switch the arguments around:
db.data.aggregate(
[
{ $project: {
_id: 0,
b: 1,
start: 1,
result: {
$subtract: [ "$b", "$start" ] } }
}
]
).pretty()
Result:
uncaught exception: Error: command failed: {
"ok" : 0,
"errmsg" : "cant $subtract adate from a double",
"code" : 16556,
"codeName" : "Location16556"
} : aggregate failed :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:18:14
_assertCommandWorked@src/mongo/shell/assert.js:618:17
assert.commandWorked@src/mongo/shell/assert.js:708:16
DB.prototype._runAggregate@src/mongo/shell/db.js:266:5
DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1046:12
@(shell):1:1
We get an error telling us that it can’t subtract a date from a double.
Return the Difference Between Two Dates
If both arguments are dates, then the $subtract operator returns the difference between the two dates in milliseconds.
Example:
db.data.aggregate(
[
{ $project: {
_id: 0,
start: 1,
end: 1,
result: {
$subtract: [ "$end", "$start" ] } }
}
]
).pretty()
Result:
{
"start" : ISODate("2021-01-03T00:00:00Z"),
"end" : ISODate("2021-01-03T23:30:15.100Z"),
"result" : NumberLong(84615100)
}
If we switch the dates around, the result becomes a negative value:
db.data.aggregate(
[
{ $project: {
_id: 0,
start: 1,
end: 1,
result: {
$subtract: [ "$start", "$end" ] } }
}
]
).pretty()
Result:
{
"start" : ISODate("2021-01-03T00:00:00Z"),
"end" : ISODate("2021-01-03T23:30:15.100Z"),
"result" : NumberLong(-84615100)
}
Passing the Wrong Number of Arguments
The $subtract operator accepts exactly two arguments. Passing the wrong number of arguments results in an error.
Example:
db.data.aggregate(
[
{ $project: {
result: {
$subtract: [ "$a" ] } }
}
]
)
Result:
uncaught exception: Error: command failed: {
"ok" : 0,
"errmsg" : "Invalid $project :: caused by :: Expression $subtract takes exactly 2 arguments. 1 were passed in.",
"code" : 16020,
"codeName" : "Location16020"
} : aggregate failed :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:18:14
_assertCommandWorked@src/mongo/shell/assert.js:618:17
assert.commandWorked@src/mongo/shell/assert.js:708:16
DB.prototype._runAggregate@src/mongo/shell/db.js:266:5
DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1046:12
@(shell):1:1
Passing Null Values
Passing two null values results in null being returned.
Example:
db.data.aggregate(
[
{ $project: {
result: {
$subtract: [ null, null ] } }
}
]
)
Result:
{ "_id" : 1, "result" : null }