[SERVER-17765] Mongodb update with array where select statement uses another array fails to update the document. Created: 27/Mar/15  Updated: 28/Mar/15  Resolved: 28/Mar/15

Status: Closed
Project: Core Server
Component/s: Internal Code
Affects Version/s: 2.6.4, 3.0.1
Fix Version/s: None

Type: Bug Priority: Minor - P4
Reporter: Jeffrey Porter Assignee: Ramon Fernandez Marina
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Operating System: ALL
Steps To Reproduce:

Create doc in TEST collection...

{
    "_id" : ObjectId("5510070f7baa49e5db605c89"),
    "cacheIds" : [ 
        "456"
    ],
    "expectedSteps" : [ 
        {
            "name" : "CacheBuildProcessor",
            "state" : "ENDED"
        }, 
        {
            "name" : "CacheProcessors",
            "state" : "NOT STARTED"
        }, 
        {
            "name" : "ProductSequential",
            "state" : "NOT STARTED"
        }, 
        {
            "name" : "PriceSequential",
            "state" : "NOT STARTED"
        }, 
        {
            "name" : "Data to CSV",
            "state" : "NOT STARTED"
        }, 
        {
            "name" : "CreateDeliveries",
            "state" : "NOT STARTED"
        }
    ]
}

run query...

db.getCollection('TEST').update(
{
"cacheIds" : "456" , 
"expectedSteps" : { 
"$elemMatch" :
 { "name" : "CreateDeliveries" , "state" : "NOT STARTED"}
 }
},
{
   $set: {"expectedSteps.$.state" : "ENDED"}
}
);

Expected : 'CreateDeliveries' last element is updated from NOT STARTED to ENDED.

Actual : 'CreateDeliveries' firstelement is updated from NOT STARTED to ENDED.

Participants:

 Description   

I have an array of items, and I want to update the one with a name of 'CreateDeliveries' and a state of 'NOT STARTED'.

The problem is this just updates the first element in the array, not the one that matches (i.e. the last element).



 Comments   
Comment by Ramon Fernandez Marina [ 28/Mar/15 ]

jeff_porter, as described in the documentation this behavior is expected:

the positional $ operator acts as a placeholder for the first element that matches the query document

I simplified your example for clarity, so consider the following document:

db.foo.drop()
db.foo.insert(
{
    "array1" : [ "1", "2", "3" ],
    "array2" : [
        {
            "name"  : "first",
            "state" : "NOT STARTED"
        }, 
        {
            "name"  : "second",
            "state" : "NOT STARTED"
        }
    ]
});

If array1 appears in the query, whatever element matches that part of the query will be considered the value for the positional operator; for example, if I use 1 it doesn't matter that the document I want to match in array2 is in position 2:

db.foo.update( { "array1" : "1" , "array2" : { "$elemMatch" :{ "name" : "second" , "state" : "NOT STARTED"}}},
{
   $set: {"array2.$.state" : "ENDED"}
}
);
db.foo.findOne()
{
        "_id" : ObjectId("5516b9dbea8545e94ca0b805"),
        "array1" : [ "1", "2", "3" ],
        "array2" : [
                {
                        "name" : "first",
                        "state" : "ENDED"
                },
                {
                        "name" : "second",
                        "state" : "NOT STARTED"
                }
        ]
}

Hope that helps.

Generated at Thu Feb 08 03:45:30 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.