Array Expression Operators
Array expression operators work inside aggregation pipelines — in $project, $addFields, $group accumulators, and $match with $expr. They inspect and transform arrays without changing stored documents.
Array expressions in aggregation
Array expression operators work inside aggregation pipelines — in $project, $addFields, $group accumulators, and $match with $expr. They inspect and transform arrays without changing stored documents.
Real-life example: These operators are like a teacher counting how many subjects a student takes, reading the first subject on the list, or merging two class rosters — all in one report query.
- $isArray — true if the value is an array
- $size — number of elements (must know array size at query time)
- $arrayElemAt — pick element by index (0-based)
- $concatArrays — join two or more arrays
- $reverseArray — reverse element order
$isArray and $size
$isArray returns a boolean — useful when documents might store a single value or an array depending on age of the schema.
$size returns the element count. It errors if the field is not an array — pair it with $isArray in conditional logic.
Real-life example: $size is counting items in a shopping cart before checkout — 'does this order have exactly 3 line items?'
db.orders.aggregate([
{
$project: {
orderId: 1,
itemCount: { $size: "$items" },
tagsIsArray: { $isArray: "$tags" },
hasManyItems: { $gt: [{ $size: "$items" }, 5] }
}
}
])
// Find orders with exactly 1 item (using $expr in find)
db.orders.find({
$expr: { $eq: [{ $size: "$items" }, 1] }
})$arrayElemAt — index into an array
$arrayElemAt takes an array and a zero-based index. Negative indices count from the end: −1 is the last element.
Real-life example: $arrayElemAt is grabbing the first name on a waitlist or the most recent entry in a log array.
db.students.aggregate([
{
$project: {
name: 1,
primarySubject: { $arrayElemAt: ["$subjects", 0] },
latestGrade: { $arrayElemAt: ["$grades", -1] }
}
}
])
// Safe access when array might be empty — use $ifNull
db.students.aggregate([
{
$addFields: {
topSubject: {
$ifNull: [
{ $arrayElemAt: ["$subjects", 0] },
"Undeclared"
]
}
}
}
])$concatArrays and $reverseArray
$concatArrays joins arrays in order — like stapling two lists together.
$reverseArray flips order — handy for 'newest first' display without sorting objects.
Real-life example: $concatArrays merges 'morning batch' and 'evening batch' student lists into one attendance sheet.
db.products.aggregate([
{
$project: {
name: 1,
allTags: {
$concatArrays: [
{ $ifNull: ["$tags", []] },
{ $ifNull: ["$autoTags", []] }
]
}
}
},
{
$project: {
name: 1,
allTags: 1,
tagsNewestFirst: { $reverseArray: "$allTags" }
}
}
])
// Combine with $setUnion for unique tags (bonus)
db.products.aggregate([
{
$addFields: {
uniqueTags: { $setUnion: ["$tags", "$autoTags"] }
}
}
])Practical report: cart summary
Array expressions shine when embedded arrays hold line items, grades, or event history. Compute derived fields in the database instead of looping in Node.js.
Real-life example: A Rishtaara canteen app stores each student's weekly orders as an array — one aggregation returns total snacks bought without loading every document into the server.
db.orders.aggregate([
{ $match: { status: "completed" } },
{
$addFields: {
lineCount: { $size: "$items" },
firstItemName: { $arrayElemAt: ["$items.name", 0] }
}
},
{
$group: {
_id: "$userId",
orderCount: { $sum: 1 },
totalLines: { $sum: "$lineCount" }
}
},
{ $sort: { totalLines: -1 } },
{ $limit: 10 }
])