[SERVER-2592] The fields in a document are reordered (sorted alphabetically) when setting a field value Created: 19/Feb/11  Updated: 01/May/23  Resolved: 14/Aug/13

Status: Closed
Project: Core Server
Component/s: Write Ops
Affects Version/s: 1.8.0-rc0
Fix Version/s: 2.5.2

Type: Bug Priority: Major - P3
Reporter: Sridhar Nanjundeswaran Assignee: Andrew Morrow (Inactive)
Resolution: Done Votes: 7
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

OS X. 1.8.0_rc0


Issue Links:
Depends
depends on SERVER-6399 Refactor update() code Closed
Duplicate
is duplicated by SERVER-12412 Update an element in an array without... Closed
Related
related to SERVER-76705 Fields are reordered alphabetically b... Closed
is related to SERVER-2991 Nice to have bson fields returned in ... Open
is related to DOCS-50 geo-spatial indexes could be damaged ... Closed
Operating System: ALL
Participants:

 Description   

The fields in a document are reordered when the size of the value stored in it changes (increases or decreases)

Case 1: No change in size of field, so no change in field order
db.testcol.find()
db.testcol.save(

{a:1,c:3,b:2}

)
db.testcol.find()

{ "_id" : ObjectId("4d5efc3bec5855af36834f5a"), "a" : 1, "c" : 3, "b" : 2 }

db.testcol.update(

{a:1}

,{$set:{c:22}})
db.testcol.find()

{ "_id" : ObjectId("4d5efc3bec5855af36834f5a"), "a" : 1, "c" : 22, "b" : 2 }

Case 2: Field size changes and the fields are reodered
db.testcol.find()
db.testcol.save(

{a:1,c:"foo",b:2,d:4}

)
db.testcol.find()

{ "_id" : ObjectId("4d5efdceec5855af36834f5e"), "a" : 1, "c" : "foo", "b" : 2, "d" : 4 }

db.testcol.update(

{a:1}

,{$set:{c:"foobar"}})
db.testcol.find()

{ "_id" : ObjectId("4d5efdceec5855af36834f5e"), "a" : 1, "b" : 2, "c" : "foobar", "d" : 4 }

Case 3: Field size changes and the fields are reordered. Note : the _id field is moved to the last field on the node
> db.testcol.find()
> db.testcol.save(

{A:1,C:"foo",B:2,D:4}

)
> db.testcol.find()

{ "_id" : ObjectId("4d5f16ceec5855af36834f60"), "A" : 1, "C" : "foo", "B" : 2, "D" : 4 }

> db.testcol.update(

{A:1}

,{$set:{C:"f"}})
> db.testcol.find()

{ "A" : 1, "B" : 2, "C" : "f", "D" : 4, "_id" : ObjectId("4d5f16ceec5855af36834f60") }

 Comments   
Comment by Dwight Merriman [ 02/Nov/12 ]

i'd vote for maintaining order on updates, i find it nonintuitive and confusing when things move around.

> db.bar.find()
{ "_id" : 123, "x" : 2, "y" : 4, "z" : 4 }
{ "_id" : 124, "x" : 1, "y" : 3, "z" : 2 }
> 
> db.bar.update( {x:2 }, { $inc : { y:1,z : 2 }, $set : {q:3} }, false, true )
> db.bar.find()
{ "_id" : 124, "x" : 1, "y" : 3, "z" : 2 }
{ "_id" : 123, "q" : 3, "x" : 2, "y" : 5, "z" : 6 }
> 

Comment by Arun Bhalla [ 24/Apr/12 ]

More motivation for why this can be an issue: SERVER-5691.

Comment by Scott Hernandez (Inactive) [ 19/Jun/11 ]

It is just the fields at the level you are modifying.

The _id field is not reordered like other embedded fields.

> db.s2592.insert({_id:{b:1, a:1}})
> db.s2592.insert({_id:{a:1, b:1}})
> db.s2592.update({_id:{b:1, a:1}}, {$set:{v:1}})
> db.s2592.find()
{ "_id" :

{ "a" : 1, "b" : 1 }

}
{ "_id" :

{ "b" : 1, "a" : 1 }

, "v" : 1 }

Comment by Thilo Planz [ 19/Jun/11 ]

Does this also happen to embedded documents when they themselves are not updated (i.e. just other parts of the document are modified)? Also, are there situations when this can happen even when the document is never updated (something like rebuilding databases, for example). I am asking because I am using embedded documents as _id fields and range queries against those (as I was advised on the mailing list that this would work), so field reordering on the _id document would be really bad. I am, however, never updating the _id field itself (and usually not even the document at all). So can I still hope to not be affected by this issue?

Comment by Stephane Jouanneau [ 09/Apr/11 ]

// My problem is the same...

// First create a record
db.sample.save({_id:1, last:"jones", first:"steve"}); // lastname, then firstname...
db.sample.find();

{ "_id" : 1, "last" : "jones", "first" : "steve" }

// Correct

// Then add a field with "$set"
db.sample.update({_id:1}, {$set:{country:"france"}});
db.sample.find();

{ "_id" : 1, "country" : "france", "first" : "steve", "last" : "jones" }

// Bad : all fields are resorted...

// I hope an option will be available soon for "$set" such as "end","begin" or "after" such as :
db.sample.update({_id:1}, {$set:{country:"france", $option:"end"}});
db.sample.find();

{ "_id" : 1, "last" : "jones", "first" : "steve", "country" : "france" }
Comment by Scott Hernandez (Inactive) [ 19/Feb/11 ]

I've updated the docs: http://www.mongodb.org/display/DOCS/Updating#Updating-Field%28re%29order

Comment by Scott Hernandez (Inactive) [ 19/Feb/11 ]

Here is the example when a unique index exists on an embedded document and a re-order breaks things.

> db.test1.ensureIndex(

{a:1}

,

{unique:true}

)
> db.test1.save({_id:1, b:2, c:3, a:{a:2, b:1}}
> db.test1.update({}, {$set:{"a.c": 3}}, true, true)
E11001 duplicate key on update

Comment by Scott Hernandez (Inactive) [ 19/Feb/11 ]

Yes, when range queries are applied to an embedded doc for one.

> db.test1.save({_id:

{b:1, a:2}

, b:2, c:3, a:{b:1, a:2}}
> db.test1.find({a:{$gte :

{b:1, a:2}

}})
{ "_id" :

{ "b" : 1, "a" : 2 }

, "b" : 2, "c" : 3, "a" :

{ "b" : 1, "a" : 2 }

}
> db.test1.update({}, {$set:{"a.c": 3}}, true, true)
> db.test1.find({a:{$gte :

{b:1, a:2}

}})
> db.test1.findOne()
{
"_id" :

{ "b" : 1, "a" : 2 }

,
"a" :

{ "a" : 2, "b" : 1, "c" : 3 }

,
"b" : 2,
"c" : 3
}
If you try to live by having the least number of surprises then this fails. I know why the _id field is not reordered, but what about other unique index fields which are on embedded docs?

Comment by Eliot Horowitz (Inactive) [ 19/Feb/11 ]

This is intentional.
Is there a case where this is an issue?

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