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.