title: MongoDB aggregate selective project
body: <p>I am running into problems reshaping my document during aggregation for grouping. Basically I want to push entries to fields depending in their type. I have a structure as follows:</p>
  
  <pre><code>_id: P1
     entities: [{type: A, val: X}, {type: B, val: X}, {type: A, val: Y}]
     ...
  </code></pre>
  
  <p>I want to $unwind and $project these entities so that get a structure like:</p>
  
  <pre><code>_id: P1
     A: [X]
     B: []
  _id: P1
     A: [Y]
     B: []
  _id: P1
     A: []
     B: [X]
  </code></pre>
  
  <p>so i can perform a grouping by A or B or both, i.e.</p>
  
  <pre><code>$group: {
     _id: {
         A: $A, 
         B: $B
      }
      count: {$sum : 1}
  </code></pre>
  
  <p>I thought I could simply do:</p>
  
  <pre><code>$unwind: $entities
  $project: {
     id: §id
     A: {"$cond":[{"$eq":["$type","A"]},"$code"]}
     B: {"$cond":[{"$eq":["$type","B"]},"$code"]}
  }
  $group: {
    _id: "$id"
    A: {$addToSet : "$A"}
  }
  </code></pre>
  
  <p>or failing that something like</p>
  
  <pre><code>$unwind: $entities
  $group: {
    _id: "$id"
    A: {"$cond":[{"$eq":["$type","A"]},$push: "$code", null]}
    ...
  }
  </code></pre>
  
  <p>but both versions fail because I cannot do nothing on else and I did not manage to use $push inside a conditional. The closest I got is project depending on the type, but since I could not find a way not to add anything to the field when there was no match, I end up with:</p>
  
  <pre><code>_id: P1
     A: [X,null,Y]
     B: [null,X,null]
  </code></pre>
  
  <p>which messes up the counting. My second idea was to filter the arrays to remove null. But I did not find a way to remove entities, because again $cond wouldnt let me specify an empty/"do nothing" else case.</p>
  
  <p>I have a feeling it could work with grouping by type and content with matching of the required types, but because I have many types and arbitrary groupings resulting in a grouping tree, this might become very complicated. Ideas or hints to mistakes would be very welcome.</p>
  
  <p>Thank you</p>
  
  <p><strong>EDIT:</strong> The solution based on the accepted anwser</p>
  
  <p>I had to slightly adapt it, to filter cases where all content of a type was null, because otherwise it would have been lost during matching and because I want to keep that knowledge. Thanks!</p>
  
  <pre><code>{$project:{
    A: {$cond: [
        {$eq: ["$A", [false]]},
        ["N/A"],
        "$A"
    ]},
    B: {$cond: [
        {$eq: ["$B", [false]]},
        ["N/A"],
        "$B"
    ]},
  }},
  { "$unwind": "$A" },
  { "$match": { "A": { "$ne": false } } },
  { "$group": {
      "_id": "$_id",
      "A": { "$push": "$A" },
      "B": { "$first": "$B" }
  }},
  { "$unwind": "$B" },
  { "$match": { "B": { "$ne": false } } },
  { "$group": {
      "_id": "$_id",
      "A": { "$first": "$A" },
      "B": { "$push": "$B" }
  }}
  </code></pre>