[SERVER-1175] findandmodify with query containing $lt causes positional ($) operator mismatch Created: 31/May/10  Updated: 29/May/12  Resolved: 03/Jun/10

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

Type: Bug Priority: Major - P3
Reporter: PowerMeMobile Assignee: Mathias Stearn
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Ubuntu 9.10 (on VMWare 6.5.1 under Windows 7)


Participants:

 Description   

Bugfix #SERVER-1095 works only for straightforward usage.
We faced that adding $lt condition on integer field to the query of findandmodify operation causes $-operator mismatch.
Here is some code to reproduce the bug:

> db.test.insert( {PhoneNumber:"12345678", MessageParts:[

{PartID:"a", Status:0, Timestamp:123456}

,

{PartID:"b", Status:0, Timestamp:123456}

]} )
> db.test.find()
{ "_id" : ObjectId("4c03d543299e2826314acf56"), "PhoneNumber" : "12345678", "MessageParts" : [

{ "PartID" : "a", "Status" : 0, "Timestamp" : 123456 }

,

{ "PartID" : "b", "Status" : 0, "Timestamp" : 123456 }

] }

// Note that we try to conditionally update the second part with ID = "b". In this case item should be updated.

> db.runCommand({findandmodify:"test", query:{PhoneNumber:"12345678", "MessageParts.PartID":"b", "MessageParts.Timestamp":{ $lt:123459 }},
... update:{ $set:

{"MessageParts.$.Status": 1, "MessageParts.$.Timestamp":123460}

}})
{
"value" : {
"_id" : ObjectId("4c03d543299e2826314acf56"),
"PhoneNumber" : "12345678",
"MessageParts" : [

{ "PartID" : "a", "Status" : 0, "Timestamp" : 123456 }

,

{ "PartID" : "b", "Status" : 0, "Timestamp" : 123456 }

]
},
"ok" : 1
}

// Unexpected behaviour: another item is updated.

> db.test.find()
{ "_id" : ObjectId("4c03d543299e2826314acf56"), "PhoneNumber" : "12345678", "MessageParts" : [

{ "PartID" : "a", "Status" : 1, "Timestamp" : 123460 }

,

{ "PartID" : "b", "Status" : 0, "Timestamp" : 123456 }

] }

// without conditions ($lt) everything works fine
> db.runCommand({findandmodify:"test", query:

{PhoneNumber:"12345678", "MessageParts.PartID":"b"}

,
... update: { $set:

{"MessageParts.$.Status":2}

} })
{
"value" : {
"_id" : ObjectId("4c03d543299e2826314acf56"),
"PhoneNumber" : "12345678",
"MessageParts" : [

{ "PartID" : "a", "Status" : 1, "Timestamp" : 123460 }

,

{ "PartID" : "b", "Status" : 0, "Timestamp" : 123456 }

]
},
"ok" : 1
}
> db.test.find()
{ "_id" : ObjectId("4c03d543299e2826314acf56"), "PhoneNumber" : "12345678", "MessageParts" : [

{ "PartID" : "a", "Status" : 1, "Timestamp" : 123460 }

,

{ "PartID" : "b", "Status" : 2, "Timestamp" : 123456 }

] }
>



 Comments   
Comment by Mathias Stearn [ 03/Jun/10 ]

You need to use $elemMatch if you want to match more than one field on a single element on the array.

This will do what you want:
db.test.findAndModify({query:{PhoneNumber:"12345678", MessageParts: {$elemMatch:{PartID:"b", Timestamp:{ $lt:123459 }}}}, update: {$set:

{"MessageParts.$.Status": 1, "MessageParts.$.Timestamp":123460}

}})

Generated at Thu Feb 08 02:56:17 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.