db.getCollection("orders").aggregate([
{ $match: {
purchase_date: { $gt: ISODate("2021-08-15"), $lt: ISODate("2021-08-23") }] },
} },
{ $set: {
line_item_ids: { $map: { input: "$line_items", in: "$$this.product_id" } },
} },
{ $lookup: {
from: "products",
localField: "line_item_ids",
foreignField: "_id",
as: "products",
} },
{ $set: {
label: { $cond: {
if: { $lt: [{ $size: "$line_items" }, 6] },
then: "small", else: { $cond: {
if: { $gte: [{ $size: "$line_items" }, 12] },
then: "large",
else: "medium"
} }
} },
} },
{ $project: {
line_item_ids: true,
label: true,
tags: true,
customer_id: true,
} }
])
$count
Default to labelling the field "count":
Humongo input
aggregate users:
match name = "Fred"
count
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $match: {
name: { $eq: "Fred" },
} },
{ $count: "count" }
])
Specify the field name:
Humongo input
aggregate users:
count as user_count
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $count: "user_count" }
])
$group
Humongo input
aggregate users:
group by signup_date:
count = sum(1)
list = push($$ROOT)
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $group: {
_id: "$signup_date",
count: { $sum: 1 },
list: { $push: "$$ROOT" },
} }
])
$limit
Humongo input
aggregate users:
limit 1000
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $limit: 1000 }
])
$lookup
Called 'import' in Humongo:
Humongo input
aggregate users:
import subs from subscriptions by customerId using _id
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $lookup: {
from: "subscriptions",
localField: "_id",
foreignField: "customerId",
as: "subs",
} }
])
Omitting the collection name will cause collection name to be the same as the new field name. Omitting the localField will cause the localField to be the same as the collection name. Omitting foreignField defaults to '_id'.
Humongo input
aggregate users:
import subscriptions
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $lookup: {
from: "subscriptions",
localField: "subscriptions",
foreignField: "_id",
as: "subscriptions",
} }
])
To import a single element, use 'import one'.
Humongo input
aggregate users:
import one order from orders using orderIds
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $lookup: {
from: "orders",
localField: "orderIds",
foreignField: "_id",
as: "order",
} }
,
{ $set: { order: { $arrayElemAt: ["$order", 0] } } }
])
$match
Tersely, on one line:
Humongo input
aggregate subscriptions:
match name = "john"
JS/Mongo query language output
db.getCollection("subscriptions").aggregate([
{ $match: {
name: { $eq: "john" },
} }
])
Or spread across multiple lines:
Humongo input
aggregate subscriptions:
match:
name = "john"
timestamp < "2021-08-23", > "2021-08-15"
JS/Mongo query language output
db.getCollection("subscriptions").aggregate([
{ $match: {
name: { $eq: "john" },
timestamp: { $and: [{ $lt: "2021-08-23" }, { $gt: "2021-08-15" }] },
} }
])
$project
Fields that should be directly projected can be listed on one line separated by commas.
Humongo input
aggregate users:
project:
age, birth_date
name = last_name
address = street_address_1
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $project: {
age: true,
birth_date: true,
name: "$last_name",
address: "$street_address_1",
} }
])
$set
Tersely, on one line:
Humongo input
aggregate users:
set name = "john"
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $set: {
name: "john",
} }
])
Or spread across multiple lines:
Humongo input
aggregate users:
set:
name = "john"
age = 47
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $set: {
name: "john",
age: 47,
} }
])
$sortByCount
Humongo input
aggregate users:
count by size(orders)
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $sortByCount: { $size: "$orders" } }
])
$unwind
Humongo input
aggregate users:
unwind orders
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $unwind: "$orders" }
])
Interpolate raw JavaScript
Use single-quotes to interpolate raw JavaScript (or anything else).
Humongo input
aggregate users:
match name = "fred"
'{ $set: { tags: { $concat: ["$tags", ", checked"] } } }'
unwind orders
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $match: {
name: { $eq: "fred" },
} },
{ $set: { tags: { $concat: ["$tags", ", checked"] } } },
{ $unwind: "$orders" }
])
Array Element Access
Use C-style array element access.
Humongo input
aggregate users:
set first_order = orders[0]
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $set: {
first_order: { $arrayElemAt: ["$orders", 0] },
} }
])
Array and object literals
Array and object literals work like you expect.
Humongo input
aggregate items:
set list = [ 1, 2, "thing", { stuff: "junk" } ]
JS/Mongo query language output
db.getCollection("items").aggregate([
{ $set: {
list: [1, 2, "thing", { stuff: "junk" }],
} }
])
Humongo input
aggregate users:
set order = { dog: "fido", cat: "snuffles" }
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $set: {
order: { dog: "fido", cat: "snuffles" },
} }
])
Complex Operators
For MongoDB operators that require a spec object, simply pass the object using function notation.
Humongo input
aggregate users:
project:
orders = map({
input: orders,
in: $$this.id
})
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $project: {
orders: { $map: { input: "$orders", in: "$$this.id" } },
} }
])
Conditionals
Use C-style ternary syntax for conditional expressions.
Humongo input
aggregate things:
set tag = size(things) > 5 ? "big" : "small"
JS/Mongo query language output
db.getCollection("things").aggregate([
{ $set: {
tag: { $cond: { if: { $gt: [{ $size: "$things" }, 5] }, then: "big", else: "small" } },
} }
])
Dates
Date literals consist of @@ followed by a date in ISO format.
Humongo input
aggregate orders:
match purchase_date <= @@2021-08-15, > @@2021-08-07
JS/Mongo query language output
db.getCollection("orders").aggregate([
{ $match: {
purchase_date: { $and: [{ $lte: ISODate("2021-08-15") }, { $gt: ISODate("2021-08-07") }] },
} }
])
Functions
Most operators are verbatim from MongoDB, using standard function invocation notation. Note that 'all' and 'any' alias 'allElementsTrue' and 'anyElementTrue'. And some operators that require an extra array wrapping do not require it in Humongo.
Humongo input
aggregate things:
set:
xyz = cos(abc)
abc = split(name, ",")
def = all(one, two, three, four)
JS/Mongo query language output
db.getCollection("things").aggregate([
{ $set: {
xyz: { $cos: "$abc" },
abc: { $split: ["$name", ","] },
def: { $allElementsTrue: ["$one", "$two", "$three", "$four"] },
} }
])
Interpolating JavaScript
Use single quotes to interpolate JavaScript in the place of any valid expression.
Humongo input
aggregate users:
match date < 'moment().subtract(5, "days").toDate()'
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $match: {
date: { $lt: moment().subtract(5, "days").toDate() },
} }
])
ObjectIDs
ObjectID literals begin with '#' followed by 12 hexadecimal digits
Humongo input
aggregate users:
match _id = #111111111111
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $match: {
_id: { $eq: ObjectId("111111111111") },
} }
])
Operators
Most operators (+, -, <) work like you'd expect. Note that '@' aliases Mongo's '$in' (both in query operations and expressions)
Humongo input
aggregate users:
match name @ ["john", "fred", "george"]
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $match: {
name: { $in: ["john", "fred", "george"] },
} }
])
Type conversion
Use `as` to convert to different types (as well as Upper and Lower case).
Humongo input
aggregate users:
set price = cost as Decimal
JS/Mongo query language output
db.getCollection("users").aggregate([
{ $set: {
price: { $toDecimal: "$cost" },
} }
])