[SERVER-59309] update with aggregation pipeline and array position not working as expected Created: 12/Aug/21  Updated: 17/Aug/21  Resolved: 17/Aug/21

Status: Closed
Project: Core Server
Component/s: None
Affects Version/s: 4.4.8
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Andreas Hald Assignee: Edwin Zhou
Resolution: Duplicate Votes: 0
Labels: Bug
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
duplicates SERVER-24748 Aggregation does not provide a way to... Backlog
Operating System: ALL
Participants:

 Description   

If you attempt to update an array on a document using the dot notation the result is not correct

Given the document

 

{
  _id: ObjectId('1234'),
  myArray: [
   {
      someValue: false
   },
   {
      someValue: true
   }
  ]
}

and the operation

 

collection.findOneAndUpdate(new ObjectId('1234'), {
   $set: {
      'myArray.0.someValue': true,
      'myArray.1.someValue': true,
   }
})

the result is as expected

 

{
 _id: ObjectId('1234'),
 myArray: [
    {
       someValue: true
    },
    {
       someValue: true
    }
 ]
}

But if I supply the same $set operation as part of an aggregation pipeline the result is very different

 

 

collection.findOneAndUpdate(new ObjectId('1234'), [
 $set: {
    'myArray.0.someValue': true,
    'myArray.1.someValue': true,
 }
]})

 

 

The result is as follows

 

{
 _id: ObjectId('1234'),
 myArray: [
    {
       someValue: false,
       0: { someValue: true},
       1: { someValue: true},
    },
    {
       someValue: true
       0: { someValue: true},
       1: { someValue: true},
    }
  ]
}

 

 

 

 



 Comments   
Comment by Edwin Zhou [ 17/Aug/21 ]

Hi ah@21risk.com,

I apologize for the delay and thank you for your patience while I investigate this issue. Thank you for correcting the repro script; I'm now able to see the issue you're running into.

This appears to describe SERVER-58521, which duplicates SERVER-24748, so I will now close this ticket as a duplicate of SERVER-24748. If you need further assistance troubleshooting or finding a workaround, I encourage you to ask our community by posting on the MongoDB Developer Community Forums.

Best,
Edwin

Comment by Andreas Hald [ 17/Aug/21 ]

Hi again Edwin, were you able to reproduce the issue with my update repro.js?

 

Best, Andreas

Comment by Andreas Hald [ 12/Aug/21 ]

Hi Edwin, thanks for getting back to me so quickly.

As I tried to explain when providing an update query directly it works as expected, just as you do in the repro.js, however if you provide the same updateQuery as part of an aggregation pipeline, it works differently.

I've modified repro.js here

 

database = db.getSiblingDB("test")
coll = database.getCollection("test_col")
coll.drop()
coll.insert({
   _id: 1,
   myArray: [
   {       
      someValue: false
   }, {            
      someValue: true        
   }    
]})
 
printjson(coll.find({ _id: 1 }).toArray())
 
coll.findOneAndUpdate(
   { _id: 1 }, 
   [   
      {        
         $set: {            
            'myArray.0.someValue': true,            
            'myArray.1.someValue': true,        
         }    
      }
   ]
)
 
printjson(coll.find({ _id: 1 }).toArray())

 

As you can see the only change I've made is that the $set operation in the findOneAndUpdate is nested in an array. This appears to be valid in the docs (https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate/#use-an-aggregation-pipeline-for-updates) however the result is wrong.

I apologise for not explaining it well enough the first time. 
Best, Andreas

 

Comment by Edwin Zhou [ 12/Aug/21 ]

Hi ah@21risk.com,

Thanks for your report. I was unable to reproduce your behavior and based on the reproduction script below, I was able to receive your expected result:

repro.js

database = db.getSiblingDB("test")
coll = database.getCollection("test_col")
coll.drop()
coll.insert({
  _id: 1,
  myArray: [
   {
      someValue: false
   },
   {
      someValue: true
   }
  ]
})
 
printjson(coll.find({_id: 1}).toArray())
 
coll.findOneAndUpdate({_id: 1}, {
  $set: {
     'myArray.0.someValue': true,
     'myArray.1.someValue': true,
  }
})
 
printjson(coll.find({_id: 1}).toArray())

result:

[
        {
                "_id" : 1,
                "myArray" : [
                        {
                                "someValue" : false
                        },
                        {
                                "someValue" : true
                        }
                ]
        }
]
[
        {
                "_id" : 1,
                "myArray" : [
                        {
                                "someValue" : true
                        },
                        {
                                "someValue" : true
                        }
                ]
        }
]

You can run the script with the following command (sans any authentication connection parameters):

mongo repro.js

Can you confirm that you're working on MongoDB v4.4.8, and can you work with the script I provided above to reproduce the issue you're seeing?

Best,
Edwin

Generated at Thu Feb 08 05:46:55 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.