Core Server
  1. Core Server
  2. SERVER-2592

The fields in a document are reordered (sorted alphabetically) when setting a field value

    Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major - P3 Major - P3
    • Resolution: Fixed
    • Affects Version/s: 1.8.0-rc0
    • Fix Version/s: 2.5.2
    • Component/s: Write Ops
    • Labels:
      None
    • Environment:
      OS X. 1.8.0_rc0
    • Backport:
      No
    • Operating System:
      ALL
    • # Replies:
      9
    • Last comment by Customer:
      false
    • Driver changes needed?:
      No driver changes needed

      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") }

        Issue Links

          Activity

          Hide
          Eliot Horowitz
          added a comment -

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

          Show
          Eliot Horowitz
          added a comment - This is intentional. Is there a case where this is an issue?
          Hide
          Scott Hernandez
          added a comment -

          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?

          Show
          Scott Hernandez
          added a comment - 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?
          Hide
          Scott Hernandez
          added a comment -

          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

          Show
          Scott Hernandez
          added a comment - 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
          Hide
          Scott Hernandez
          added a comment -
          Show
          Scott Hernandez
          added a comment - I've updated the docs: http://www.mongodb.org/display/DOCS/Updating#Updating-Field%28re%29order
          Hide
          Stephane Jouanneau
          added a comment -

          // 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" }
          Show
          Stephane Jouanneau
          added a comment - // 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" }
          Hide
          Thilo Planz
          added a comment -

          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?

          Show
          Thilo Planz
          added a comment - 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?
          Hide
          Scott Hernandez
          added a comment -

          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 }

          Show
          Scott Hernandez
          added a comment - 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 }
          Hide
          Arun Bhalla
          added a comment -

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

          Show
          Arun Bhalla
          added a comment - More motivation for why this can be an issue: SERVER-5691 .
          Hide
          Dwight Merriman
          added a comment -

          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 }
          > 
          Show
          Dwight Merriman
          added a comment - 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 } >

            People

            • Votes:
              7 Vote for this issue
              Watchers:
              11 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since reply:
                1 year, 24 weeks, 2 days ago
                Date of 1st Reply: