Details
-
Bug
-
Resolution: Duplicate
-
Major - P3
-
None
-
None
-
Query
-
Minor Change
-
ALL
Description
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.