title: MongoDB aggregate object map to distinct values
body: <p>I got three documents:</p>
  
  
  
  <pre class="lang-js prettyprint-override"><code>[
    { _id: 1, article: 1, details: { color: "red" } },
    { _id: 2, article: 1, details: { color: "blue", size: 44 },
    { _id: 3, article: 2, details: { color: "blue", size: 44 }
  ]
  </code></pre>
  
  <p>which I want to transform in a query to:</p>
  
  <pre class="lang-js prettyprint-override"><code>[
    { article: 1, details: { color: ["red", "blue"], size: [44] } },
    { article: 2, details: { color: ["blue"], size: [44] }
  ]
  </code></pre>
  
  <p>at the moment this is achieved by mapReduce:</p>
  
  <pre class="lang-js prettyprint-override"><code>db.varieties.mapReduce(map, reduce, { out: { inline: 1 } });
  
  function map() {
    for (var key in this.details) {
      this.details[key] = [this.details[key]];
    }
  
    emit(this.article, this.details);
  }
  
  function reduce(article, details) {
    var result = {};
  
    details.forEach(function(detail) {
      for (var key in detail) {
        if (!Array.isArray(result[key])) result[key] = [];
        if (~result[key].indexOf(detail[key])) result[key].concat(detail[key]);
      }
    });
    return result;
  }
  </code></pre>
  
  <p>However I would like to do this through the mongodb aggregation frame work as the map reduce implementation in my environment is very "difficult".</p>
  
  <p>Regarding the aggregation I am so far:</p>
  
  <pre class="lang-js prettyprint-override"><code>var pipeline = [];
  
  pipeline.push({ $project: { article: 1, details: 1 } });
  pipeline.push({ $group: { _id: "$article", details: { $push: '$details' } });
  
  db.varieties.aggregate(pipeline);
  </code></pre>
  
  <p>However this will just return:</p>
  
  <pre class="lang-js prettyprint-override"><code>[
    { article: 1, details: [{ color: "red", size: 44 }, { color: "blue", size: 44 }] },
    { article: 2, details: [{ color: "blue", size: 44 }]
  ]
  </code></pre>
  
  <p>I read somewhere that this a use case for <code>$unwind</code> unfortunately this will not work on objects.</p>
  
  <p>So lets get to my questions:</p>
  
  <ol>
  <li>Is it possible to somehow convert the <code>details</code> object to an array with <code>{ key: "color", value: "red" }</code> and if yes how to achieve this?</li>
  <li>If the above is not possible and I would restructure my documents to the be stored in the above format (details as array) how would I need to complete my aggregation to get the same result from my origin mapReduce?</li>
  </ol>
  
  <p><strong>I cannot hardcode the keys of details. The aggregation must work on details of unknown keys.</strong></p>