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 }