In MongoDB, the $log
aggregation pipeline operator calculates the log of a number in the specified base and returns the result as a double.
Syntax
The syntax goes like this:
{ $log: [ <number>, <base> ] }
Where:
<number>
can be any valid expression that resolves to a non-negative number.<base>
can be any valid expression that resolves to a positive number greater than1
.
Example
Suppose we have a collection called test
with the following document:
{ "_id" : 1, "data" : 0.5 } { "_id" : 2, "data" : 20 } { "_id" : 3, "data" : 200 }
We can use the $log
operator to return the log base 10 of the data
field:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 1, 2, 3 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $log: [ "$data", 10 ] }
}
}
]
)
Result:
{ "data" : 0.5, "result" : -0.30102999566398114 } { "data" : 20, "result" : 1.301029995663981 } { "data" : 200, "result" : 2.301029995663981 }
Another way of doing this would have been to use the $log10
operator.
However, $log10
only returns the log base 10 of a number. With $log
, on the other hand, we can specify the base to use.
Here’s an example of specifying a base of 16:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 1, 2, 3 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $log: [ "$data", 16 ] }
}
}
]
)
Result:
{ "data" : 0.5, "result" : -0.25 } { "data" : 20, "result" : 1.0804820237218407 } { "data" : 200, "result" : 1.910964047443681 }
Natural Logarithm
The natural logarithm of a number is its logarithm to the base of the mathematical constant e, where e is an irrational and transcendental number that starts off with 2.7182818284590452353602874713527 and continues on forever.
The mathematical constant e is also known as Euler’s number.
In JavaScript, we can use Math.E
to represent e. We can therefore get the natural logarithm of a number by using Math.E
as the second argument when using $log
.
Example:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 1, 2, 3 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $log: [ "$data", Math.E ] }
}
}
]
)
Result:
{ "data" : 0.5, "result" : -0.6931471805599453 } { "data" : 20, "result" : 2.995732273553991 } { "data" : 200, "result" : 5.298317366548036 }
Bear in mind that MongoDB also has the $ln
operator, which is specifically designed to return the natural logarithm of a number, so you might find it easier to use that operator instead. See MongoDB $ln
for an example.
Out of Range Values
As mentioned, the $log
operator accepts any valid expression that resolves to a non-negative number. Values outside of that range will cause an error.
Suppose we add the following document to our collection:
{ "_id" : 4, "data" : -20 }
Let’s run the the $log
operator against that document:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 4 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $log: [ "$data", 16 ] }
}
}
]
)
Result:
uncaught exception: Error: command failed: { "ok" : 0, "errmsg" : "$log's argument must be a positive number, but is -20", "code" : 28758, "codeName" : "Location28758" } : aggregate failed : _getErrorWithCode@src/mongo/shell/utils.js:25:13 doassert@src/mongo/shell/assert.js:18:14 _assertCommandWorked@src/mongo/shell/assert.js:639:17 assert.commandWorked@src/mongo/shell/assert.js:729:16 DB.prototype._runAggregate@src/mongo/shell/db.js:266:5 DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1058:12 @(shell):1:1
Wrong Data Type
Providing the wrong data type will also cause an error.
Suppose we add the following document to our collection:
{ "_id" : 5, "data" : "Ten" }
Let’s run the the $log
operator against that document:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 5 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $log: [ "$data", 16 ] }
}
}
]
)
Result:
uncaught exception: Error: command failed: { "ok" : 0, "errmsg" : "$log's argument must be numeric, not string", "code" : 28756, "codeName" : "Location28756" } : aggregate failed : _getErrorWithCode@src/mongo/shell/utils.js:25:13 doassert@src/mongo/shell/assert.js:18:14 _assertCommandWorked@src/mongo/shell/assert.js:639:17 assert.commandWorked@src/mongo/shell/assert.js:729:16 DB.prototype._runAggregate@src/mongo/shell/db.js:266:5 DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1058:12 @(shell):1:1
We provided a string, and so the error message tells us that $log's argument must be numeric, not string
.
Null Values
Null values return null
when using the $log
operator.
Suppose we add the following document to our collection:
{ "_id" : 6, "data" : null }
Let’s run the the $log
operator against that document:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 6 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $log: [ "$data", 16 ] }
}
}
]
)
Result:
{ "data" : null, "result" : null }
We can see that the result is null
.
NaN Values
If the argument resolves to NaN
, $log
returns NaN
.
Example:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 1 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $log: [ "$data" * 1, 16 ] }
}
}
]
)
Result:
{ "data" : 0.5, "result" : NaN }
Non-Existent Fields
If the $log
operator is applied against a field that doesn’t exist, null
is returned.
Example:
db.test.aggregate(
[
{ $match: { _id: { $in: [ 1 ] } } },
{
$project:
{
_id: 0,
data: 1,
result: { $log: [ "$age", 16 ] }
}
}
]
)
Result:
{ "data" : 0.5, "result" : null }
In this case we tried to apply $log
against a field called age
, but that field doesn’t exist in the document, and so we get null
.