10. Transforming Arrays with $map, $filter, and $reduce

Use $map to transform every array element, $filter to retain elements that satisfy a condition, and $reduce to accumulate a result across an array. These expressions can preserve one pipeline document per parent document, unlike $unwind.

Use as to name the current element in $map and $filter; reference it with $$variable. In $reduce, $$value is the accumulated result and $$this is the current element.

Array expressions generally expect array input. $ifNull can turn a missing or null array into an empty array, but it does not convert arbitrary non-array values into arrays.

Choose the right array technique

$map transforms elements, $filter selects elements, and $reduce accumulates a result. Use $unwind when later stages need each element as a separate document.

Code Example
db.orders.aggregate([
  {
    $set: {
      electronicsItems: {
        $filter: {
          input: { $ifNull: ["$items", []] },
          as: "item",
          cond: { $eq: ["$$item.category", "Electronics"] }
        }
      }
    }
  },
  {
    $set: {
      electronicsSubtotal: {
        $reduce: {
          input: "$electronicsItems",
          initialValue: 0,
          in: { $add: ["$$value", { $multiply: ["$$this.quantity", "$$this.price"] }] }
        }
      }
    }
  }
]);
Key Takeaways
  • $map transforms elements.
  • $filter selects elements.
  • $reduce accumulates a value.
  • Array expressions can avoid document expansion.
Knowledge Check

Which operator returns only array elements whose category is Electronics?