Flattening a nested MongoDB Document

时间:2017-06-15 09:26:32

标签: mongodb mongodb-query

This is a follow up to

Flatten a nested object in MongoDB and rename

After using the mentioned answer on that , some of the data types get accepted and they are flattened out while some throw error

  can't convert undefined to object

For example:- A document on which the data fails:-

{
  "id" : "1415304490",
  "color" : {
      "1391" : "Grey"
  },
  "name":"Random Name"
}

And the corrosponding function I am using:-

db.suggestion.find().forEach(function(doc) {
  var color;
  Object.keys(doc.color).forEach(function(key) {
    color = doc.color[key];
  });

    db.suggestion.update(
       { _id: doc._id },
       { $set: 
           { color: color } 
       }
    );
}) 

It ran on 20,000 prior documents but now failing on this document.

Also If i try to run the same code by running it on a single id , i.e

     db.suggest.find({id:"12"})

It again works fine as it should be on the same document it was failing earlier.

I also tried to create a work-around as it was running for finding one document each, i.e

db.suggestion.find().forEach(function(dest) {
  var id_temp=dest.id;

  db.suggestion.find({id:id_temp}).forEach(function(doc) {
    var color;
    Object.keys(doc.color).forEach(function(key) {
      color = doc.color[key];
    });

    db.suggestion.update(
       { _id: doc._id },
       { $set: 
           { color: color } 
       }
    );
  }) 
})

It still fails. I am quite unsure of this weird behaviour of the code.

1 个答案:

答案 0 :(得分:1)

Use $exists to make sure the color key is actually present. This is why you are getting the error.

var ops = [];

db.collection.find({ "color": { "$exists": true } }).forEach(function(doc) {
  var color;
  Object.keys(doc.color).forEach(function(key) {
    color = doc.color[key];
  });
  ops.push(
    { "updateOne": {
      "filter": { "_id": doc._id },
      "update": { "$set": { "color": color } }
    }}
  );
  if ( ops.length >= 500 ) {
    db.collection.bulkWrite(ops);
     ops = [];
  }
})

if ( ops.length > 0 ) {
  db.collection.bulkWrite(ops);
   ops = [];
}

Set up a document:

db.collection.insert(
 {
   "id" : "1415304490",
   "color" : {
       "1391" : "Grey"
   },
   "name":"Random Name"
 }
)

Run the supplied code on that and get:

db.collection.find().pretty()
{
        "_id" : ObjectId("59430fc4fc23376431161e52"),
        "id" : "1415304490",
        "color" : "Grey",
        "name" : "Random Name"
}