1

I have tried the below query of mongoose which does not seem to work:

Model.findOneAndUpdate(
    {
        name: origin
    },
    {
        $set: {
            'field1.$[id1].field2.-1': "value"
        }
    },
    {
        arrayFilters: [
            { 'id1.userId': "customerId" }
        ],
        new: true
    }
);

Note: field1 and field2 are arrays

The negative indexes are not accepted by MongoDB which is causing problems.

2 Answers2

1

You may consider using the $set (aggregation) operator and use double $map operator:

db.collection.aggregate([
    { $match: { name: "myname" } }
    {
        $set: {
            field1: {
                $map: {
                    input: "$field1",
                    in: {
                        $cond: {
                            if: { $ne: [ "$$this.userId", "customerId" ] },
                            then: "$$this",
                            else: {
                                $mergeObjects: [
                                    "$$this",
                                    { 
                                        field2: { 
                                            $concatArrays: [
                                                { $slice: [ "$$this.field2", { $add: [ { $size: "$$this.field2" }, -1 ] } ] },
                                                ["value"]
                                            ]
                                        } 
                                    }
                                ]
                            }
                        }
                    }
                }
            }
        }
    }
])

Mongo Playground

mickl
  • 48,568
  • 9
  • 60
  • 89
  • This solution does the job. However, the issue here is that this will map through every element even after the required element is updated. Is there a way to optimize this query further? (There will only be 1 element which will satisfy the condition) – ABHISHEK Joshi Dec 21 '21 at 14:07
  • 1
    @ABHISHEKJoshi no other single round-trip solution comes to my mind, you can wait for others to respond. Since negative indexes are not allowed you need to know the index of your last element and this requires to query the document first. In my solution everything is processed on the database side – mickl Dec 21 '21 at 14:10
  • I'm getting this error: `MongoServerError: Updating the path 'analysis' would create a conflict at 'analysis'`. Please note that I'm using `findOneAndUpdate()` and not `aggregate()`. – ABHISHEK Joshi Dec 21 '21 at 17:24
  • @ABHISHEKJoshi I think it requires aggregate – mickl Dec 21 '21 at 21:54
  • Actually I wanted updated document to be returned. That's the reason I used `findOneAndUpdate`. Maybe I'll have to query the DB twice. I guess that's the only way to go. – ABHISHEK Joshi Dec 22 '21 at 03:12
0

Apply the $set operator together with the $ positional operator in your update to change the name field.

The $ positional operator will identify the correct element in the array to update without explicitly specifying the position of the element in the array, thus your final update statement should look like:

db.collection.update(
    { "friends.u.username": "michael" }, 
    { "$set": { "friends.$.u.name": "hello" } }
)

Answer taken from - https://stackoverflow.com/a/34431571

maxagno3
  • 110
  • 2
  • 9
  • 1
    As mentioned in the title, I want to update last element of nested array. Your solution updates any element which satisfies the condition in 1st argument of the `update` function and not specifically the last element. So this cannot be a valid solution. – ABHISHEK Joshi Dec 21 '21 at 15:52