In MongoDB, the $filter
aggregation pipeline operator returns a subset of an array based on a specified condition.
The $filter
operator returns an array with only those elements that match the condition, in their original order.
Syntax
The syntax goes like this:
{ $filter: { input: <array>, as: <string>, cond: <expression> } }
Each field is as explained below.
Field | Specification |
---|---|
input | An expression that resolves to an array. |
as | This is an optional field. It specifies a name for the variable that represents each individual element of the input array. If no name is specified (i.e. if you omit this field), the variable name defaults to this . |
cond | An expression that resolves to a boolean value used to determine if an element should be included in the output array. The expression references each element of the input array individually with the variable name specified in as . |
Example
Suppose we have a collection called players
with the following documents
{ "_id" : 1, "player" : "Homer", "scores" : [ 1, 5, 3 ] } { "_id" : 2, "player" : "Marge", "scores" : [ 8, 17, 18 ] } { "_id" : 3, "player" : "Bart", "scores" : [ 15, 11, 8 ] }
Here’s an example of applying the $filter
operator to filter the array elements in the scores
field:
db.players.aggregate([
{
$match: { _id: { $in: [ 1, 2, 3 ] } }
},
{
$project: {
highScores: {
$filter: {
input: "$scores",
as: "score",
cond: { $gt: [ "$$score", 10 ] }
}
}
}
}
])
Result:
{ "_id" : 1, "highScores" : [ ] } { "_id" : 2, "highScores" : [ 17, 18 ] } { "_id" : 3, "highScores" : [ 15, 11 ] }
In this example, we filtered the arrays to just those elements that have a value greater than 10. Only those values are returned.
Any values that are less than 10 are omitted from the result. In the case of the first document, this results in an empty array.
Here, we used the as
field to name the return variable score
. We then referred to that variable in the cond
field using $$score
. As mentioned, you can omit the as
field, and then refer to the return variable using $$this
. More on this later.
Empty Arrays
If the array is empty, then an empty array is returned.
Suppose we have the following document in our collection:
{ "_id" : 4, "player" : "Farnsworth", "scores" : [ ] }
Here’s what happens when we apply $filter
to that array:
db.players.aggregate([
{
$match: { _id: { $in: [ 4 ] } }
},
{
$project: {
highScores: {
$filter: {
input: "$scores",
as: "score",
cond: { $gt: [ "$$score", 10 ] }
}
}
}
}
])
Result:
{ "_id" : 4, "highScores" : [ ] }
Wrong Type
Applying $filter
to a field that doesn’t contain an array returns an error.
Example:
db.players.aggregate([
{
$match: { _id: { $in: [ 4 ] } }
},
{
$project: {
highScores: {
$filter: {
input: "$player",
as: "player",
cond: { $gt: [ "$$player", 10 ] }
}
}
}
}
])
Result:
Error: command failed: { "ok" : 0, "errmsg" : "input to $filter must be an array not string", "code" : 28651, "codeName" : "Location28651" } : 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
Null Values
If the field contains null
instead of an array, the result is null
.
Imagine we have the following document in the collection:
{ "_id" : 5, "player" : "Meg", "scores" : null }
Here’s what happens when we apply $filter
to the scores
field:
db.players.aggregate([
{
$match: { _id: { $in: [ 5 ] } }
},
{
$project: {
highScores: {
$filter: {
input: "$scores",
as: "score",
cond: { $gt: [ "$$score", 10 ] }
}
}
}
}
])
Result:
{ "_id" : 5, "highScores" : null }
Non-Existent Field
Applying $filter
to a field that doesn’t exist results in null
being returned.
Example:
db.players.aggregate([
{
$match: { _id: { $in: [ 5 ] } }
},
{
$project: {
highScores: {
$filter: {
input: "$name",
as: "name",
cond: { $gt: [ "$$name", 10 ] }
}
}
}
}
])
Result:
{ "_id" : 5, "highScores" : null }
The Variable Name is Optional
In the previous examples, I use the as
field to assign a name to the variable.
As mentioned, the as
field is optional. If you omit this field, the variable name defaults to this
.
Here’s an example:
db.players.aggregate([
{
$match: { _id: { $in: [ 1, 2, 3 ] } }
},
{
$project: {
highScores: {
$filter: {
input: "$scores",
cond: { $gt: [ "$$this", 10 ] }
}
}
}
}
])
Result:
{ "_id" : 1, "highScores" : [ ] } { "_id" : 2, "highScores" : [ 17, 18 ] } { "_id" : 3, "highScores" : [ 15, 11 ] }
This is the same as the first example, except in this example, we omit the as
field, and therefore refer to the variable using $$this
.