MongoDB Push with positional operator not working

I have the following document in the users collection

{
    "_id" : "388179687996974",
    "matches" : [ 
        {
            "userId" : "1495728740672094",
            "choice" : false,
            "dates" : [],
            "dateId" : null
        }, 
        {
            "userId" : "385516561596016",
            "choice" : true,
            "dates" : [],
            "dateId" : "2014-11-26_385516561596016_388179687996974"
        }, 
        {
            "userId" : "253752728167114",
            "choice" : false,
            "dates" : [],
            "dateId" : null
        }, 
        {
            "userId" : "365296866955687",
            "choice" : null,
            "dates" : [ 
                "2014-11-26"
            ],
            "dateId" : null
        }
    ],
    "playDates" : [ 
        "2014-11-26"
    ]       
}

      

I have the following request

db.users.find({
  "_id":{"$ne":"385516561596016"},
  "playDates":{"$in":["2014-11-26"]},
  "matches":{"$elemMatch":{
        "userId":"385516561596016",
        "dates":{"$nin":["2014-11-26"]}}}})

      

It returns the above document.

I am trying to update a document using the positional statement like this:

db.users.update({
    "_id":{"$ne":"385516561596016"}, 
    "playDates":{"$in":["2014-11-26"]},
    "matches":{"$elemMatch":{"userId":"385516561596016",
          "dates":{"$nin":["2014-11-26"]}}}}, 
    {"$push":{"matches.$.dates":"2014-11-26"}})

      

Instead of putting 2014-11-26 in match for userId 385516561596016, it puts it in matches [0].

What am I doing wrong?

+3


source to share


3 answers


It smells like a mongodb bug. I've tried a couple of different options.

db.items.update({
"_id":{"$ne":"385516561596016"},     
    //without the playDates $in clause
"matches":{"$elemMatch":{"userId":"253752728167114"} } } , 
{"$push":{"matches.$.dates":"test"} } )

      

This works as expected by placing "test" in the third item.

This is not a bug with the $ push operator, as $ set gets confused too:



db.items.update({
"_id":{"$ne":"385516561596016"},     
"playDates":{"$in":["2014-11-26"]},
"matches":{"$elemMatch":{"userId":"253752728167114"} } } , 
{"$set":{"matches.$.other":"bob"} } ) 
//fails


db.items.update({
"_id":{"$ne":"385516561596016"},     
"matches":{"$elemMatch":{"userId":"253752728167114"} } } , 
{"$set":{"matches.$.other":"joe"} } )
//success

      

I think you should report this to JIRA. https://jira.mongodb.org/secure/Dashboard.jspa (If you're lucky they can fix this in a year. So far they've fixed my 1/8 problems).

In the meantime, perhaps you can change your application so that the $ request in the playDates request is not needed?

+2


source


The problem is that you are requesting two arrays in one request: playDates

and matches

.

MongoDB is putting your data in matches[0]

because your query matches playDates[0]

with {"$in":["2014-11-26"]}

, so MongoDB binds $

to its index 0.



Unfortunately, I don't know how to fix this without deleting the "playDates":{"$in":["2014-11-26"]}

part.

+1


source


The problem is when you are trying to match values ​​from two different arrays - matches

and playDates

- in the same request document. This is currently not supported in MongoDB.

According to dos :

The request document must contain only one condition for the array Projected field. Multiple conditions can override each other internally and lead to undefined behavior.

According to these requirements, the following query is incorrect:

 db.collection.find( { <array>: <value>, <someOtherArray>: <value2> },
                    { "<array>.$": 1 } )

      

Since using $

to update the corresponding document in one of the arrays results in behavior undefined

, the workaround would be to run two queries, one to find the document, the other to update it once the values ​​change in the application code.

+1


source







All Articles