1
votes

Using MongoDB, I'm doing an aggregation pipeline on a document that contains an array called tests, and using an $unwind operation to unwind that array into several documents:

Original document:

{"_id"=>"1867930", "tests"=> [
    {"status"=>"passed", "elapsed_time"=>26, "worker"=>11},
    {"status"=>"passed", "elapsed_time"=>34, "worker"=>13},
    {"status"=>"passed", "elapsed_time"=>23, "worker"=>15}
]}

Result after $unwind:

{"_id"=>"1867930", "tests"=>{"status"=>"passed", "elapsed_time"=>26, "worker"=>11}}
{"_id"=>"1867930", "tests"=>{"status"=>"passed", "elapsed_time"=>34, "worker"=>13}}
{"_id"=>"1867930", "tests"=>{"status"=>"passed", "elapsed_time"=>23, "worker"=>15}}

How can I apply another operation to hoist the values of the tests key in each of these documents up a level (i.e. eliminating the duplicate tests keys created from the $unwind) to get the following result?

{"_id"=>"1867930", "status"=>"passed", "elapsed_time"=>26, "worker"=>11}
{"_id"=>"1867930", "status"=>"passed", "elapsed_time"=>34, "worker"=>13}
{"_id"=>"1867930", "status"=>"passed", "elapsed_time"=>23, "worker"=>15}

Note that this is not renaming the tests key, it's moving the value of tests up a level and merging with the parent hash.

1
Duplicates? What does this have to do with duplicates? Surely all you are asking is how to make "tests.status" etc into just "status". That is what you are asking right? Just renaming keys. - Blakes Seven
@BlakesSeven no, this is not renaming, it's moving the value of tests and merging it into the parent. - Ken Liu
Yes it is renaming. Just as the answer on the linked duplicate does, and just as the answer added here that is a copy of that response does. That is the way you do it. With JavaScript manipulation of mapReduce you could do something more generic such as adding to the parent. But your question like the other is about the aggregation framework. - Blakes Seven

1 Answers

1
votes

Try to do it through $project

db.collection.aggregate([
  {$unwind: '$tests'}, 
  {$project: 
     {status: '$tests.status', 
      elapsed_time: '$tests.elapse_time',
      worker: '$tests.worker'}}
]);

Or do it as following with cursor forEach to print the data format

db.collection.find({ "tests": {"$exists": 1 }}).forEach(
   function(doc){
      for (var i in doc.tests){
         doc.tests[i]._id = doc._id; 
         printjson(doc.tests[i]);
      }
   });