Filtered Positional Operator in MongoDB – A Complete Guide

Filtered Positional Operator In Mongodb Featured Image

In this tutorial, I will discuss the filtered positional operator in MongoDB.

The filtered positional operator in MongoDB, denoted as $[] is used to identify the array elements that match the array filter conditions during the update operation.

In order to use the filtered positional operator in the update statement, the query must include an exact equality match on the array field if an upsert operation results in an insert. Please note that fields with numeric names will be processed in numeric order.

This guide aims to provide examples o how to use the filtered positional operator in MongoDB. So, let us get started!

The Filtered Positional Operator Syntax

Let us take a quick look at the filtered positional operator in MongoDB.

Using with the arrayFilters options:

{ updateOperator: { "arrayField.$[identifier]" : value } },
{ arrayFilters: [ { identifier: condition } ] }

Using to match the arrayFilters conditions or query conditions:

db.collection.updateMany(
   { query conditions },
   { update operator: { "arrayField.$[identifier]" : value } },
   { arrayFilters: [ { identifier: condition } ] }
)

Using the Filtered Positional Operator in MongoDB

Let us get started with some examples of how to use the filtered positional operator in MongoDB.

Let us use the testGrades database for this guide that contains an array of grades of each student in every document.

This is what our grades collection looks like:

> db.grades.find().pretty()
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6762"),
        "name" : "John Mendes",
        "grades" : [
                82,
                85,
                88,
                90,
                78
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6763"),
        "name" : "Sofia Derulo",
        "grades" : [
                70,
                75,
                68,
                65,
                70
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6764"),
        "name" : "Areesha Shaikh",
        "grades" : [
                86,
                89,
                93,
                90,
                88
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6765"),
        "name" : "Grace Handles",
        "grades" : [
                55,
                65,
                63,
                68,
                70
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6766"),
        "name" : "Rebecca Chism",
        "grades" : [
                82,
                78,
                80,
                91,
                75
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6767"),
        "name" : "David Hudson",
        "grades" : [
                67,
                70,
                78,
                74,
                72
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6768"),
        "name" : "Latonya Jacobson",
        "grades" : [
                80,
                87,
                84,
                95,
                81
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6769"),
        "name" : "Luigi Markham",
        "grades" : [
                82,
                73,
                79,
                80,
                71
        ]
}

Updating All Array Elements that Match arrayFilters Options

Let us use the filtered positional operator in MongoDB to update all elements of the grades array of all documents. We want to look for those elements that are greater than or equal to 90 grade and change them to 100.

  • This is how we will conduct the operation:
> db.grades.updateMany(
...    { },
...    { $set: { "grades.$[element]" : 100 } },
...    { multi: true,
...      arrayFilters: [ { "element": { $gte: 90 } } ]
...    }
... )

{ "acknowledged" : true, "matchedCount" : 8, "modifiedCount" : 4 }

We can see that 4 out of 8 documents were matched and were modified.

  • Let us see what the documents now look like:
> db.grades.find().pretty()
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6762"),
        "name" : "John Mendes",
        "grades" : [
                82,
                85,
                88,
                100,
                78
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6763"),
        "name" : "Sofia Derulo",
        "grades" : [
                70,
                75,
                68,
                65,
                70
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6764"),
        "name" : "Areesha Shaikh",
        "grades" : [
                86,
                89,
                100,
                100,
                88
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6765"),
        "name" : "Grace Handles",
        "grades" : [
                55,
                65,
                63,
                68,
                70
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6766"),
        "name" : "Rebecca Chism",
        "grades" : [
                82,
                78,
                80,
                100,
                75
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6767"),
        "name" : "David Hudson",
        "grades" : [
                67,
                70,
                78,
                74,
                72
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6768"),
        "name" : "Latonya Jacobson",
        "grades" : [
                80,
                87,
                84,
                100,
                81
        ]
}
{
        "_id" : ObjectId("618d1b3ca485bcfe795e6769"),
        "name" : "Luigi Markham",
        "grades" : [
                82,
                73,
                79,
                80,
                71
        ]
}

The filtered positional operator acted successfully!

Updating All Documents that Match Multiple Conditions

Let us try to update all documents that match multiple conditions given to the filtered positional operator.

Let us use a different collection called grades2 for this example. We are doing so because we want to work with embedded documents inside arrays.

So, this is what the array looks like:

> db.grades2.find().pretty()
{
        "_id" : ObjectId("618d282aa485bcfe795e676a"),
        "grades" : [
                {
                        "grade" : 70,
                        "mean" : 65,
                        "standard" : 7
                },
                {
                        "grade" : 65,
                        "mean" : 90,
                        "standard" : 8
                },
                {
                        "grade" : 95,
                        "mean" : 85,
                        "standard" : 10
                }
        ]
}
{
        "_id" : ObjectId("618d282aa485bcfe795e676b"),
        "grades" : [
                {
                        "grade" : 70,
                        "mean" : 90,
                        "standard" : 6
                },
                {
                        "grade" : 89,
                        "mean" : 80,
                        "standard" : 3
                },
                {
                        "grade" : 60,
                        "mean" : 100,
                        "standard" : 4
                }
        ]
}
{
        "_id" : ObjectId("618d282aa485bcfe795e676c"),
        "grades" : [
                {
                        "grade" : 80,
                        "mean" : 100,
                        "standard" : 5
                },
                {
                        "grade" : 85,
                        "mean" : 70,
                        "standard" : 6
                },
                {
                        "grade" : 90,
                        "mean" : 80,
                        "standard" : 2
                }
        ]
}
{
        "_id" : ObjectId("618d282aa485bcfe795e676d"),
        "grades" : [
                {
                        "grade" : 50,
                        "mean" : 70,
                        "standard" : 3
                },
                {
                        "grade" : 79,
                        "mean" : 90,
                        "standard" : 2
                },
                {
                        "grade" : 67,
                        "mean" : 60,
                        "standard" : 1
                }
        ]
}

We have 4 documents.

Let us modify the values of the standard field for all elements inside the grades array. We want to pick only those elements of all those documents that have grade greater than or equal to 90 and standard than equal to 7. We are using the filtered positional operator for this operation with the arrayFilters option.

> db.grades2.updateMany(
...    { },
...    { $inc: { "grades.$[elem].standard" : -1 } },
...    { arrayFilters: [ { "elem.grade": { $gte: 90 }, "elem.standard": { $gt: 7 } } ], multi: true }
... )
{ "acknowledged" : true, "matchedCount" : 4, "modifiedCount" : 1 }

It looks like the operator found 1 matching document and modified it.

  • Let us look at the documents again:
> db.grades2.find().pretty()
{
        "_id" : ObjectId("618d282aa485bcfe795e676a"),
        "grades" : [
                {
                        "grade" : 70,
                        "mean" : 65,
                        "standard" : 7
                },
                {
                        "grade" : 65,
                        "mean" : 90,
                        "standard" : 8
                },
                {
                        "grade" : 95,
                        "mean" : 85,
                        "standard" : 9
                }
        ]
}
{
        "_id" : ObjectId("618d282aa485bcfe795e676b"),
        "grades" : [
                {
                        "grade" : 70,
                        "mean" : 90,
                        "standard" : 6
                },
                {
                        "grade" : 89,
                        "mean" : 80,
                        "standard" : 3
                },
                {
                        "grade" : 60,
                        "mean" : 100,
                        "standard" : 4
                }
        ]
}
{
        "_id" : ObjectId("618d282aa485bcfe795e676c"),
        "grades" : [
                {
                        "grade" : 80,
                        "mean" : 100,
                        "standard" : 5
                },
                {
                        "grade" : 85,
                        "mean" : 70,
                        "standard" : 6
                },
                {
                        "grade" : 90,
                        "mean" : 80,
                        "standard" : 2
                }
        ]
}
{
        "_id" : ObjectId("618d282aa485bcfe795e676d"),
        "grades" : [
                {
                        "grade" : 50,
                        "mean" : 70,
                        "standard" : 3
                },
                {
                        "grade" : 79,
                        "mean" : 90,
                        "standard" : 2
                },
                {
                        "grade" : 67,
                        "mean" : 60,
                        "standard" : 1
                }
        ]
}

The operation was conducted successfully!

Conclusion

Learn to use the filtered positional operator in MongoDB.

References

https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#mongodb-update-up.—identifier–