MongoDB $zip Operator

Beginner
⏱️ 8 min read
📚 Updated: Jul 2026
🎯 5 Examples
Arrays

What You’ll Learn

The $zip operator merges parallel arrays element by element inside MongoDB aggregation pipelines. Each output item is a sub-array containing the values at the same index from every input array — like pairing columns in a spreadsheet row.

01

Merge Arrays

Pair by index.

02

Syntax

inputs + options.

03

Shortest Wins

Default length rule.

04

Padding

useLongestLength.

05

Build Objects

Zip + $map.

06

vs $concatArrays

Zip vs append.

Definition and Usage

In MongoDB’s aggregation framework, the $zip operator takes two or more arrays and combines them by index. If you have names: ["Alice", "Bob"] and scores: [90, 85], zipping them produces [["Alice", 90], ["Bob", 85]].

This is useful when related data is stored in separate parallel arrays instead of an array of objects. You can zip them together, then use $map to reshape each pair into a structured object for reporting or export.

💡
Beginner Tip

Think of $zip as stacking arrays side by side. Index 0 from each array becomes one row, index 1 becomes the next row, and so on. By default, zipping stops when the shortest array runs out of elements.

📝 Syntax

The $zip operator takes an object with an inputs array and optional length options:

mongosh
{
  $zip: {
    inputs: [ <array1>, <array2>, ... ],
    useLongestLength: <boolean>,
    defaults: <array>
  }
}

Common Patterns

mongosh
// Zip two field arrays
{
  $zip: {
    inputs: [ "$names", "$scores" ]
  }
}

// Zip three parallel arrays
{
  $zip: {
    inputs: [ "$first", "$last", "$grades" ]
  }
}

// Pad shorter arrays to longest length
{
  $zip: {
    inputs: [ "$keys", "$values" ],
    useLongestLength: true,
    defaults: [ null, 0 ]
  }
}

// Zip then build objects with $map
{
  $map: {
    input: {
      $zip: { inputs: [ "$names", "$scores" ] }
    },
    as: "pair",
    in: {
      name: { $arrayElemAt: [ "$$pair", 0 ] },
      score: { $arrayElemAt: [ "$$pair", 1 ] }
    }
  }
}

Syntax Rules

  • inputs — required array of two or more array expressions (field paths or literals).
  • useLongestLength — optional boolean; default false (stop at shortest array).
  • defaults — optional array of fallback values, one per input array, used when useLongestLength is true.
  • Output is an array of sub-arrays; each sub-array has one element from each input at the same index.
  • If any input is null or not an array, $zip returns null.
  • Use inside stages like $project, $addFields, or $set.

💡 $zip vs $concatArrays vs $map

$zip → pairs elements by index: [["a",1],["b",2]]
$concatArrays → appends into one flat array: ["a","b",1,2]
$map → transforms each element in a single array; often used after $zip
Analogy$zip = Python zip(), $concatArrays = array spread / concat

⚡ Quick Reference

QuestionAnswer
Operator typeAggregation array expression operator
Syntax{ $zip: { inputs, useLongestLength?, defaults? } }
InputTwo or more arrays (field paths or literals)
OutputArray of sub-arrays (or null)
Default lengthLength of the shortest input array
Common stages$project, $addFields, $set
Two arrays
{
  $zip: {
    inputs: [ "$a", "$b" ]
  }
}

Pair by index

Three arrays
{
  $zip: {
    inputs: [
      "$first",
      "$last",
      "$score"
    ]
  }
}

Three-column rows

Longest length
{
  $zip: {
    inputs: [ "$k", "$v" ],
    useLongestLength: true,
    defaults: [ "", 0 ]
  }
}

Pad shorter arrays

Literals
{
  $zip: {
    inputs: [
      ["x", "y"],
      [1, 2]
    ]
  }
}

Returns [["x",1],["y",2]]

Examples Gallery

Zip parallel arrays, handle mismatched lengths, pad with defaults, and reshape zipped pairs into objects using a students collection.

📚 Zip Two Parallel Arrays

Pair names with scores using the default shortest-length behavior.

Sample Input Documents

Suppose you have a students collection where names and scores are stored in separate arrays:

mongosh
[
  {
    "_id": 1,
    "className": "Math 101",
    "names": ["Alice", "Bob", "Carol"],
    "scores": [92, 85, 78]
  },
  {
    "_id": 2,
    "className": "Science 201",
    "names": ["Dave", "Eve"],
    "scores": [88, 91, 95]
  }
]

Example 1 — Basic $zip of Names and Scores

Merge names and scores into paired sub-arrays:

mongosh
db.students.aggregate([
  {
    $project: {
      className: 1,
      nameScorePairs: {
        $zip: {
          inputs: [ "$names", "$scores" ]
        }
      }
    }
  }
])

How It Works

$zip reads index 0 from each input array and builds the first sub-array, then index 1, and so on. For Science 201, names has only two items, so the extra score 95 is ignored.

📈 Multiple Arrays & Length Options

Zip three columns, control output length, and reshape results into objects.

Example 2 — Zip Three Parallel Arrays

Combine first names, last names, and grades into three-column rows:

mongosh
db.students.aggregate([
  {
    $project: {
      rows: {
        $zip: {
          inputs: [
            ["Alice", "Bob"],
            ["Smith", "Jones"],
            ["A", "B"]
          ]
        }
      }
    }
  }
])

// rows: [
//   ["Alice", "Smith", "A"],
//   ["Bob", "Jones", "B"]
// ]

How It Works

inputs accepts literal arrays as well as field paths. Each position across all three arrays becomes one sub-array in the output.

Example 3 — Default Shortest-Length Behavior

When arrays differ in length, only the shortest count is used:

mongosh
db.students.aggregate([
  {
    $project: {
      paired: {
        $zip: {
          inputs: [
            ["a", "b", "c"],
            [1, 2]
          ]
        }
      }
    }
  }
])

// paired: [["a", 1], ["b", 2]]
// "c" is dropped because the second array has only 2 elements

How It Works

With default settings (useLongestLength: false), MongoDB stops at the shortest input. This prevents mismatched pairings when one array is unexpectedly longer.

Example 4 — useLongestLength with defaults

Pad shorter arrays so every element in the longest array gets a pair:

mongosh
db.students.aggregate([
  {
    $project: {
      paired: {
        $zip: {
          inputs: [
            ["a", "b", "c"],
            [1, 2]
          ],
          useLongestLength: true,
          defaults: [ null, 0 ]
        }
      }
    }
  }
])

// paired: [["a", 1], ["b", 2], ["c", 0]]

How It Works

useLongestLength: true continues to the longest array. The defaults array supplies fill values per input column — null for missing names and 0 for missing scores.

Example 5 — Zip Then Build Objects with $map

Turn each zipped pair into a readable object for API responses or exports:

mongosh
db.students.aggregate([
  {
    $project: {
      className: 1,
      roster: {
        $map: {
          input: {
            $zip: {
              inputs: [ "$names", "$scores" ]
            }
          },
          as: "row",
          in: {
            name: { $arrayElemAt: [ "$$row", 0 ] },
            score: { $arrayElemAt: [ "$$row", 1 ] }
          }
        }
      }
    }
  }
])

// roster: [
//   { name: "Alice", score: 92 },
//   { name: "Bob", score: 85 }
// ]

How It Works

$zip creates sub-arrays; $map walks each sub-array and uses $arrayElemAt to pick index 0 (name) and index 1 (score). This is the standard pattern for converting parallel arrays into structured data.

Bonus — Zip Keys and Values for $arrayToObject

When keys and values live in separate arrays, zip them before converting to an object:

mongosh
db.students.aggregate([
  {
    $project: {
      scoreMap: {
        $arrayToObject: {
          $map: {
            input: {
              $zip: {
                inputs: [
                  ["math", "science", "english"],
                  [92, 88, 95]
                ]
              }
            },
            as: "pair",
            in: {
              k: { $arrayElemAt: [ "$$pair", 0 ] },
              v: { $arrayElemAt: [ "$$pair", 1 ] }
            }
          }
        }
      }
    }
  }
])

// scoreMap: { math: 92, science: 88, english: 95 }

How It Works

$arrayToObject expects an array of { k, v } documents. Zipping parallel key and value arrays is a clean way to build that structure. See the $arrayToObject operator tutorial for more patterns.

🚀 Use Cases

  • Parallel array cleanup — combine legacy fields stored as separate name and value arrays into structured objects.
  • Report row building — align columns (product, quantity, price) before exporting or displaying tabular data.
  • Key-value reconstruction — zip keys and values arrays, then pass to $arrayToObject.
  • CSV-style imports — merge header and data arrays after parsing flat file rows.
  • Chart data prep — pair labels with numeric series for visualization pipelines.

🧠 How $zip Works

1

MongoDB evaluates each input array

Every expression in inputs is resolved per document — field paths like "$names" or literal arrays.

Input
2

Output length is determined

By default, length equals the shortest input. With useLongestLength: true, length equals the longest input and defaults fill gaps.

Length
3

Sub-arrays are built by index

For each index i, MongoDB collects element i from every input array into one sub-array.

Zip
=

Parallel arrays merged

Pass the result to $map, $arrayToObject, or $unwind for further shaping.

Conclusion

The $zip operator merges parallel arrays element-wise in MongoDB aggregation pipelines. It is the go-to tool when related values live in separate arrays and you need to pair them by index before reshaping with $map or $arrayToObject.

Remember: default behavior stops at the shortest array. Use useLongestLength and defaults when you need every element from the longest column. Next in the series: MongoDB Accumulators.

💡 Best Practices

✅ Do

  • Verify parallel arrays have matching meaning at each index before zipping
  • Follow $zip with $map to build readable objects
  • Use useLongestLength + defaults when padding is intentional
  • Prefer arrays of objects in new schemas over parallel arrays when possible
  • Pair with $arrayToObject for key-value reconstruction

❌ Don’t

  • Confuse $zip with $concatArrays (pair vs append)
  • Assume extra elements in longer arrays are included by default
  • Zip arrays that are not aligned — index mismatches produce wrong pairings
  • Forget that null or non-array inputs return null
  • Overuse parallel arrays in schema design when embedded objects are clearer

Key Takeaways

Knowledge Unlocked

Five things to remember about $zip

Use these points when merging parallel arrays in MongoDB.

5
Core concepts
📝 02

inputs Array

Two+ arrays.

Syntax
🛠 03

Shortest Wins

Default length.

Behavior
🗃 04

+ $map

Build objects.

Pattern
05

vs $concatArrays

Zip vs append.

Compare

❓ Frequently Asked Questions

$zip merges two or more parallel arrays element by element. Each output item is a sub-array containing the values at the same index from every input array — similar to Python's zip() or JavaScript's manual index pairing.
The syntax is { $zip: { inputs: [ array1, array2, ... ], useLongestLength: <boolean>, defaults: <array> } }. Only inputs is required. By default, $zip stops at the shortest input array length.
By default, $zip uses the shortest array length and ignores extra elements in longer arrays. Set useLongestLength to true and provide defaults to pad shorter arrays and continue to the longest length.
$zip combines arrays by index into sub-arrays. $concatArrays appends arrays end-to-end into one flat array. Use $zip when columns are parallel; use $concatArrays when you want one long list.
Use $zip inside expression stages such as $project, $addFields, and $set. It is often followed by $map to turn each zipped pair into an object, or by $arrayToObject when keys and values are separate arrays.

Continue the Operator Series

You’ve reached the last expression operator. Move on to MongoDB Accumulators for grouping calculations like $sum and $avg.

Next: Accumulators →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful