0

In the application im building I have two updates that I want to do in the same query. I want to find the subdocument with the matching task_id and update its priority. In the same call I want to increment all the subdocuments with a priority higher than 3. Is it possible to combine these two in the same query?

    const project = await Project.updateOne(

        // first search
        { _id: req.params.project_id },
        { $set: {'tasks.$[element].priority': req.body.priority, 'tasks.$[element].state': req.body.state }},
        { arrayFilters: [{ 'element._id': req.params.task_id }] }


        // second search
        { _id: req.params.project_id },
        { $inc: {'tasks.$[element].priority': 1 }},
        { arrayFilters: [{ 'element.priority': { $gt: 3 } }] }
);
MVG
  • 9
  • 4

2 Answers2

0

you must be used different identifiers for your arrayFilters. your identifier is element. your code must be like that:

const project = await Project.updateOne(
    // first search
    {_id: req.params.project_id},
    {
        $set: {'tasks.$[elementA].priority': req.body.priority, 'tasks.$[elementA].state': req.body.state},
        $inc: {'tasks.$[elementB].priority': 1}
    },
    {
        arrayFilters: [
            {'elementA._id': req.params.task_id},
            {'elementB.priority': {$gt: 3}}
        ]
    },
)

NOTE: The identifier must begin with a lowercase letter and contain only alphanumeric characters (from MongoDB official website, link)

Mahdi Hashemi
  • 127
  • 2
  • 6
  • What if I wanted to add another array filter? Lets say in the $inc I add another one: '$tasks.$[elementC].priority': 2. And then in the arrayFilter I add another one with this elementC: 'elementC.priority: {$gt: 2}}. I get a conflict error :/ – MVG May 24 '20 at 11:02
0

You can do it simultaneously by using two arrayFilters. Consider the below:

Current collection:

{
    "_id" : 1,
    "array1" : [
        {
            "k1" : 1,
            "v1" : 100
        },
        {
            "k1" : 2,
            "v1" : 15
        },
        {
            "k1" : 1,
            "v1" : 100
        }
    ],
    "array2" : [
        {
            "k2" : 1,
            "v2" : 10
        },
        {
            "k2" : 2,
            "v2" : 1000
        },
        {
            "k2" : 1,
            "v2" : 20
        }
    ]
}

Query:

db.collection.update(
    { _id: 1 },
    { $set:
        {
            'array1.$[elem1].v1': 100,
            'array2.$[elem2].v2': 1000
        }
    },
    { arrayFilters: 
        [
            {'elem1.k1':1},
            {'elem2.k2': 2}
        ],
    multi: true
    }
)

As you can see that, I have created two filtered positional operator (elem1 and elem2), with the help of arrayFilters option. I can used this to perform my updates.

Result:

{
    "_id" : 1,
    "array1" : [
        {
            "k1" : 1,
            "v1" : 100
        },
        {
            "k1" : 2,
            "v1" : 15
        },
        {
            "k1" : 1,
            "v1" : 100
        }
    ],
    "array2" : [
        {
            "k2" : 1,
            "v2" : 10
        },
        {
            "k2" : 2,
            "v2" : 1000
        },
        {
            "k2" : 1,
            "v2" : 20
        }
    ]
}

You can see in the above updated collection that the k1 field in array1 with value 1, it's v1 field have been updated to 100 and the k2 field in array2 with value 2, it's v2 field have been updated to 100.

So in your case you need to do something like below:

updateOne(
    { _id: req.params.project_id},
    {
        $set: {
            'tasks.$[elem1].priority': req.body.priority,
            'tasks.$[elem1].state': req.body.state
        },
        $inc: {
            'tasks.$[elem2].priority': 1
        }
    },
    {
        arrayFilters: [
            { 'elem1._id': req.params.task_id },
            { 'elem2.priority':
                { $gt: 3 }
            }
        ]
    }
)

I hope it's helpful.

ngShravil.py
  • 4,742
  • 3
  • 18
  • 30
  • Thank you for your answer, it was very useful. What if I want to add another $inc and another arrayFilter to it? Lets say I add 'tasks.$.[elem3].priority: 2' and add this to the array filter same as with elem2. I get an update conflict. How would I go about this? – MVG May 24 '20 at 11:14
  • I did not understand your doubt, I think it will be good if you ask a separate questions and let me know. – ngShravil.py May 24 '20 at 14:19
  • Thank you I created a new question – MVG May 24 '20 at 16:56