$zip (aggregation)

Definition

  • $zip

New in version 3.4.

Transposes an array of input arrays so that the first element ofthe output array would be an array containing, the first element ofthe first input array, the first element of the second input array,etc.

For example, $zip would transform[ [ 1, 2, 3 ], [ "a", "b", "c" ] ] into[ [ 1, "a" ], [ 2, "b" ], [ 3, "c" ] ].

$zip has the following syntax:

  1. {
  2. $zip: {
  3. inputs: [ <array expression1>, ... ],
  4. useLongestLength: <boolean>,
  5. defaults: <array expression>
  6. }
  7. }

OperandDescriptioninputsAn array of expressions thatresolve to arrays. The elements of these input arrays combineto form the arrays of the output array.

If any of the inputs arrays resolves to a value of null or refers to amissing field, $zip returns null.

If any of the inputs arrays does not resolve to an array or null nor refersto a missing field, $zip returns an error.useLongestLengthA boolean which specifies whether the length of the longestarray determines the number of arrays in the output array.

The default value is false: the shortest array lengthdetermines the number of arrays in the output array.defaultsAn array of default element values to use if the input arrayshave different lengths. You must specifyuseLongestLength: true along with this field, or else$zip will return an error.

If useLongestLength: true but defaults is empty or notspecified, $zip uses null as the defaultvalue.

If specifying a non-empty defaults, you must specify adefault for each input array or else $zipwill return an error.

Behavior

The input arrays do not need to be of the same length. By default,the output array has the length of the shortest input array, but theuseLongestLength option instructs $zip to outputan array as long as the longest input array.

ExampleResults
  1. { $zip: { inputs: [ [ "a" ], [ "b" ], [ "c" ] ] }
  1. [ [ "a", "b", "c" ] ]
  1. { $zip: { inputs: [ [ "a" ], [ "b", "c" ] ] } }
  1. [ [ "a", "b" ] ]
  1. { $zip: { inputs: [ [ 1 ], [ 2, 3 ] ], useLongestLength: true }}
  1. [ [ 1, 2 ], [ null, 3 ] ]
  1. { $zip: { inputs: [ [ 1 ], [ 2, 3 ], [ 4 ] ], useLongestLength: true, defaults: [ "a", "b", "c" ] }}
Because useLongestLength: true, $zip will pad the shorterinput arrays with the corresponding defaults elements.This yields [ [ 1, 2, 4 ], [ "a", 3, "c" ] ].

Example

Matrix Transposition

A collection called matrices contains the following documents:

  1. db.matrices.insertMany([
  2. { matrix: [[1, 2], [2, 3], [3, 4]] },
  3. { matrix: [[8, 7], [7, 6], [5, 4]] },
  4. ])

To compute the transpose of each 3x2 matrix in this collection, you canuse the following aggregation operation:

  1. db.matrices.aggregate([{
  2. $project: {
  3. _id: false,
  4. transposed: {
  5. $zip: {
  6. inputs: [
  7. { $arrayElemAt: [ "$matrix", 0 ] },
  8. { $arrayElemAt: [ "$matrix", 1 ] },
  9. { $arrayElemAt: [ "$matrix", 2 ] },
  10. ]
  11. }
  12. }
  13. }
  14. }])

This will return the following 2x3 matrices:

  1. { "transposed" : [ [ 1, 2, 3 ], [ 2, 3, 4 ] ] }
  2. { "transposed" : [ [ 8, 7, 5 ], [ 7, 6, 4 ] ] }

Filtering and Preserving Indexes

You can use $zip with $filter to obtain a subset ofelements in an array, saving the original index alongside eachretained element.

A collection called pages contains the following document:

  1. db.pages.save( {
  2. "category": "unix",
  3. "pages": [
  4. { "title": "awk for beginners", reviews: 5 },
  5. { "title": "sed for newbies", reviews: 0 },
  6. { "title": "grep made simple", reviews: 2 },
  7. ] } )

The following aggregation pipeline will first zip the elements of thepages array together with their index, and then filter out only thepages with at least one review:

  1. db.pages.aggregate([{
  2. $project: {
  3. _id: false,
  4. pages: {
  5. $filter: {
  6. input: {
  7. $zip: {
  8. inputs: [ "$pages", { $range: [0, { $size: "$pages" }] } ]
  9. }
  10. },
  11. as: "pageWithIndex",
  12. cond: {
  13. $let: {
  14. vars: {
  15. page: { $arrayElemAt: [ "$$pageWithIndex", 0 ] }
  16. },
  17. in: { $gte: [ "$$page.reviews", 1 ] }
  18. }
  19. }
  20. }
  21. }
  22. }
  23. }])

This will return the following document:

  1. {
  2. "pages" : [
  3. [ { "title" : "awk for beginners", "reviews" : 5 }, 0 ],
  4. [ { "title" : "grep made simple", "reviews" : 2 }, 2 ] ]
  5. }