A colleague asked me if it's possible to generate all combinations of 2 items for a given array using aggregation pipeline expression. In other words, something that gives this:
> db.combos.find() {_id:1, a:[ 1,2,3]} > db.combos.aggregate({$project:{_id:0, pairs: <generate-all-pairs>}}) {pairs: [ [1,2], [1,3], [2,3] ]}
I'm always game to challenge aggregation so here is what I came up with for the <generate> expression for k=2:
{$reduce:{ input:{$range:[0,{$size:"$a"}]}, initialValue:[], in:{$concatArrays:[ "$$value", {$let:{ vars:{i:"$$this"}, in:{$map:{ input:{$range:[{$add:[1,"$$i"]},{$size:"$a"}]}, in:[ {$arrayElemAt:["$a","$$i"]}, {$arrayElemAt:["$a","$$this"]}] }} }} ]} }}
This is the aggregation equivalent of looping over the array elements and for each one looping over the remaining array elements to create the pairs. If array is `a` it's:
pairs = []; for (i=0; i<a.length; i++) { for (j=a[i+1]; j<a.length; j++) { pairs.push([ [a[i], a[j] ]); } }
Aggregation expressions are pretty powerful. I gave a talk about the power of expressions over arrays at MongoDB World and local events in 2017/2018: if you missed it watch it HERE.