-
Type: Bug
-
Resolution: Duplicate
-
Priority: Major - P3
-
None
-
Affects Version/s: None
-
Component/s: Index Maintenance, Write Ops
-
Query
-
Minor Change
-
ALL
The DataFileMgr::updateRecord() and getIndexChanges() code finds the index key sets for a document both pre and post update. Values present in one but not both of these key sets are added / removed from the appropriate indexes, while values present in both are untouched in the indexes. The implementation uses key equality rather than bit equivalence to determine if a key exists in both the pre and post update key set. So if a key is changed from one numeric type to another but its new value is equal to its original value, the key will not be updated in the index. As a result a covered index query can return a key with the wrong data type.
Test:
c = db.c; c.drop(); c.ensureIndex( { a:1 } ); c.save( { a:5 } ); printjson( c.find( { a:5 }, { _id:0, a:1 } ).hint( { a:1 } ).toArray() ); printjson( c.find( { a:5 }, { _id:0, a:1 } ).hint( { $natural:1 } ).toArray() ); c.update( {}, { $set:{ a:NumberLong( 5 ) } } ); // Because NumberLong( 5 ) == 5, the index key is not updated. printjson( c.find( { a:5 }, { _id:0, a:1 } ).hint( { a:1 } ).toArray() ); printjson( c.find( { a:5 }, { _id:0, a:1 } ).hint( { $natural:1 } ).toArray() ); c.remove(); c.save( { a:5 } ); obj = c.findOne(); obj.a = NumberLong( 5 ); c.update( {}, obj ); // Because NumberLong( 5 ) == 5, the index key is not updated. printjson( c.find( { a:5 }, { _id:0, a:1 } ).hint( { a:1 } ).toArray() ); printjson( c.find( { a:5 }, { _id:0, a:1 } ).hint( { $natural:1 } ).toArray() );
– Aaron
-------------------------------------------------------
run the following script:
t = db.users; t.drop(); t.insert( { age: 5, name : "xxx" } ); t.insert( { age: 5, name : "yyy" } ); t.insert( { age: 5, name : "zzz" } ); t.ensureIndex( {age: 1} ); rec = t.findOne( {name: "yyy"} ); delete rec.name; rec.age = NumberLong(5); t.update( {name: "yyy"}, rec ); t.find( {age:5}, {_id:0, age:1} )
The last output should be:
{ "age" : 5 } { "age" : NumberLong(5) } { "age" : 5 }
but actually, the output is:
{ "age" : 5 } { "age" : 5 } { "age" : 5 }
The type info is lost.