3

I am having a wiered issue, not sure what exactly i am missing.

I have a list of objects into my collection as follows..

{ "_id" : ObjectId("5340eff554f98e32c5990b4f"), "Day" : 8, "Time" : 1553, "State" : "Florida", "Airport" : "ORL", "Temperature" : 82, "Humidity" : 55, "Wind Speed" : 5, "Wind Direction" : 170, "Station Pressure" : 29.97, "Sea Level Pressure" : 196 }
{ "_id" : ObjectId("5340eff554f98e32c5990b5f"), "Day" : 9, "Time" : 1253, "State" : "Florida", "Airport" : "ORL", "Temperature" : 82, "Humidity" : 60, "Wind Speed" : 13, "Wind Direction" : 190, "Station Pressure" : 29.91, "Sea Level Pressure" : 175 }
{ "_id" : ObjectId("5340eff554f98e32c5990b60"), "Day" : 9, "Time" : 1353, "State" : "Florida", "Airport" : "ORL", "Temperature" : 82, "Humidity" : 58, "Wind Speed" : 11, "Wind Direction" : 190, "Station Pressure" : 29.88, "Sea Level Pressure" : 166 }
{ "_id" : ObjectId("5340eff554f98e32c5990b4c"), "Day" : 8, "Time" : 1253, "State" : "Florida", "Airport" : "ORL", "Temperature" : 81, "Humidity" : 54, "Wind Speed" : 4, "Wind Direction" : 180, "Station Pressure" : 30.02, "Sea Level Pressure" : 214 }

from the Node client using mongo db driver, i am executing an update query as follows. Basically it is part of the actual code where i am trying to add "month_high" flag to the object containing the highest temprature for the state.

var updateQuery = {'_id':doc['_id']};
var operator = {$set:{'month_high' : true}};                
db.collection('temps').update(updateQuery,operator,callback)

The issue is after update, it updates the correct object, but re-orders its fields like following ( Notice the first object )

{ "Airport" : "ORL", "Day" : 8, "Humidity" : 55, "Sea Level Pressure" : 196, "State" : "Florida", "Station Pressure" : 29.97, "Temperature" : 82, "Time" : 1553, "Wind Direction" : 170, "Wind Speed" : 5, "_id" : ObjectId("5340eff554f98e32c5990b4f"), "month_high" : true }
 { "_id" : ObjectId("5340eff554f98e32c5990b5f"), "Day" : 9, "Time" : 1253, "State" : "Florida", "Airport" : "ORL", "Temperature" : 82, "Humidity" : 60, "Wind Speed" : 13, "Wind Direction" : 190, "Station Pressure" : 29.91, "Sea Level Pressure" : 175 }
 { "_id" : ObjectId("5340eff554f98e32c5990b60"), "Day" : 9, "Time" : 1353, "State" : "Florida", "Airport" : "ORL", "Temperature" : 82, "Humidity" : 58, "Wind Speed" : 11, "Wind Direction" : 190, "Station Pressure" : 29.88, "Sea Level Pressure" : 166 }
 { "_id" : ObjectId("5340eff554f98e32c5990b4c"), "Day" : 8, "Time" : 1253, "State" : "Florida", "Airport" : "ORL", "Temperature" : 81, "Humidity" : 54, "Wind Speed" : 4, "Wind Direction" : 180, "Station Pressure" : 30.02, "Sea Level Pressure" : 214 }
ATHER
  • 3,254
  • 5
  • 40
  • 63
  • Are you certain it was that code that did this? It looks to me as if some other code has done this where the keys have all been ordered in the resulting update. Your new field is at the end as expected, but I think something else modified this record first. Try to re-produce. – Neil Lunn Apr 07 '14 at 05:26
  • possible duplicate of [MongoDB field order and document position change after update](http://stackoverflow.com/questions/5046835/mongodb-field-order-and-document-position-change-after-update) – Evgeniy Generalov Apr 07 '14 at 05:27
  • ok i changed my query as follows but now the order of the fields for the updated objects is not messed up. Do we really have to pass the whole doc object to the update method ?? var updateQuery = {}; updateQuery['_id'] = doc['_id']; doc['month_high'] = true; db.collection('temps').update(updateQuery,doc, callback) { – ATHER Apr 07 '14 at 05:30
  • Collections are unordered sets. You can expect that the documents are in some order only if you use the operator [sort ()](http://docs.mongodb.org/manual/reference/method/db.collection.find/#order-documents-in-the-result-set). Otherwise, the order of documents depends on the implementation. – Evgeniy Generalov Apr 07 '14 at 05:38
  • @user15328 JSON and therefore BSON specifies that the order of fields remains the same as created. Your duplicate flag is unlikely with such a small data size, and you last comment does not make much sense. Sorting documents has nothing to do with this, which is about "field" order. What is possible is that some languages (Perl for instance) do not by default maintain the the order of the hash keys as inserted, and they are in fact ordered lexically. But you can also get around that. – Neil Lunn Apr 07 '14 at 06:13
  • 1
    This is the issue: https://jira.mongodb.org/browse/SERVER-2592, it has since been fixed in 2.6 – Sammaye Apr 07 '14 at 07:14

3 Answers3

4

You can use MongoDB projection as well. (recommended way)

db.collection.find( < criteria >, < projection >);

Below is the example:

db.collection.find({},{
   "Airport":1,
   "Day":1,
   "Humidity":1,
   "Sea Level Pressure":1,
   "State":1,
   "Station Pressure":1,
   "Temperature":1,
   "Time":1,
   "Wind Direction":1,
   "Wind Speed":1,
   "_id":1,
   "month_high":1
});

Gives you the output as you expected i.e.

{
   "Airport":"ORL",
   "Day":8,
   "Humidity":55,
   "Sea Level Pressure":196,
   "State":"Florida",
   "Station Pressure":29.97,
   "Temperature":82,
   "Time":1553,
   "Wind Direction":170,
   "Wind Speed":5,
   "_id":ObjectId("5340eff554f98e32c5990b4f"),
   "month_high":true
}, ...


Another way is once you get the documents into Node.js you can Reorder the fields in JSON.

Example:

var json = {"name": "David", "age" : 78, "NoOfVisits" : 4   };
console.log(json);
//outputs - Object {name: "David", age: 78, NoOfVisits: 4}
//change order to NoOfVisits,age,name

var k = JSON.parse(JSON.stringify( json, ["NoOfVisits","age","name"] , 4));
console.log(k);
//outputs - Object {NoOfVisits: 4, age: 78, name: "David"} 

Put the key order you want in an array and supply to the function. Then parse the result back to JSON.


Reason Why It Happens:

MongoDB allocates space for a new document based on a certain padding factor. If your update increases the size of the document beyond the size originally allocated the document will be moved to the end of the collection. The same concept applies to fields in a document.

If you are really interested and want to dig into it here is the link for more information

Amol M Kulkarni
  • 21,143
  • 34
  • 120
  • 164
  • Why is the first solution recommended, is it faster than creating another json object as seen in your 2 solution? – Timo Jul 19 '22 at 15:29
1

Basically the issue you are experiencing comes down to: https://jira.mongodb.org/browse/SERVER-2592 which has been fixed in 2.6.

Document field order should be preserved from 2.6 onwards. Currently you do have to do the work around you have.

Sammaye
  • 43,242
  • 7
  • 104
  • 146
0

The following change in my query fixed the issue. Now after the update, order of the fields/properties are NOT messed up.

This code is actually grouping objects by state, and for each state, i am sorting records in descending order and adding the flag "month_high" to the object having highest temperature.

db.collection('data').aggregate([{$group:{"_id":"$State"}}],function(err,results){
    for(var i=0;i<results.length;i++){

    var query = {'State':results[i]._id};
    var cursor = db.collection('data').find(query);
        cursor.limit(1);
        cursor.sort('Temperature',-1);

        cursor.each(function(err, doc) {
            if(err) throw err;
            if(doc == null) {
                return;
            }

 // I just had to change the following query and it worked for me
 // rest of the code remains same.
                  var updateQuery = {};
               updateQuery['_id'] = doc['_id'];
        doc['month_high'] = true;

   db.collection('data').update(updateQuery,doc, function(err, updated) {
                    if(err) throw err;

                    console.dir("Successfully updated " + updated + " document!");

                    return;
                });             
            //console.dir(doc._id);
        });
  }
});

Still not sure when my query was like following why it did not worked

var updateQuery = {'_id':doc['_id']};
var operator = {$set:{'month_high' : true}};
db.collection('data').update(updateQuery,operator,callback)
ATHER
  • 3,254
  • 5
  • 40
  • 63