1. 算术表达式操作符 ($abs)
// 插入数据
db.temperatureChange.insertMany([
{ _id: 1, startTemp: 50, endTemp: 80 },
{ _id: 2, startTemp: 40, endTemp: 40 },
{ _id: 3, startTemp: 90, endTemp: 70 },
{ _id: 4, startTemp: 60, endTemp: 70 }
]);
// 计算温度差的绝对值
db.temperatureChange.aggregate([
{
$project: {
delta: { $abs: { $subtract: ["$startTemp", "$endTemp"] } }
}
}
]);
2. 数组表达式操作符 ($arrayElemAt)
// 插入数据
db.users.insertMany([
{ _id: 1, name: "dave123", favorites: ["chocolate", "cake", "butter", "apples"] },
{ _id: 2, name: "li", favorites: ["apples", "pudding", "pie"] },
{ _id: 3, name: "ahn", favorites: ["pears", "pecans", "chocolate", "cherries"] },
{ _id: 4, name: "ty", favorites: ["ice cream"] }
]);
// 获取数组首尾元素
db.users.aggregate([
{
$project: {
name: 1,
first: { $arrayElemAt: ["$favorites", 0] },
last: { $arrayElemAt: ["$favorites", -1] }
}
}
]);
3. 按位操作符 ($bitAnd)
// 插入数据
db.switches.insertMany([
{ _id: 0, a: NumberInt(0), b: NumberInt(127) },
{ _id: 1, a: NumberInt(2), b: NumberInt(3) },
{ _id: 2, a: NumberInt(3), b: NumberInt(5) }
]);
// 按位与运算
db.switches.aggregate([
{
$project: {
result: { $bitAnd: ["$a", "$b"] }
}
}
]);
4. 布尔表达式操作符 ($and)
// 插入数据
db.inventory.insertMany([
{ _id: 1, item: "abc1", qty: 300 },
{ _id: 2, item: "abc2", qty: 200 },
{ _id: 3, item: "xyz1", qty: 250 },
{ _id: 4, item: "wxz1", qty: 300 },
{ _id: 5, item: "wxz2", qty: 180 }
]);
// 检查数量范围
db.inventory.aggregate([
{
$project: {
item: 1,
qty: 1,
result: { $and: [
{ $gt: ["$qty", 100] },
{ $lt: ["$qty", 250] }
]}
}
}
]);
5. 条件表达式操作符 ($cond)
// 插入数据
db.inventory.insertMany([
{ _id: 1, item: "abc1", qty: 300 },
{ _id: 2, item: "abc2", qty: 200 },
{ _id: 3, item: "xyz1", qty: 260 }
]);
// 条件折扣计算
db.inventory.aggregate([
{
$project: {
item: 1,
discount: {
$cond: {
if: { $gte: ["$qty", 260] },
then: 30,
else: 20
}
}
}
}
]);
6. 日期操作符 ($dateAdd)
// 插入数据
db.shipping.insertMany([
{ custId: 456, purchaseDate: ISODate("2020-12-31") },
{ custId: 457, purchaseDate: ISODate("2021-02-28") },
{ custId: 458, purchaseDate: ISODate("2021-02-26") }
]);
// 计算预计交付日期(+3天)
db.shipping.aggregate([
{
$project: {
expectedDeliveryDate: {
$dateAdd: {
startDate: "$purchaseDate",
unit: "day",
amount: 3
}
}
}
}
]);
7. 字符串操作符 ($concat)
// 插入数据
db.inventory.insertMany([
{ _id: 1, item: "ABC1", description: "product 1" },
{ _id: 2, item: "ABC2", description: "product 2" },
{ _id: 3, item: "XYZ1", description: null }
]);
// 拼接字符串
db.inventory.aggregate([
{
$project: {
itemDescription: { $concat: ["$item", " - ", "$description"] }
}
}
]);
8. 累加器操作符 ($addToSet)
// 插入数据
db.sales.insertMany([
{ _id: 1, item: "abc", date: ISODate("2014-01-01T08:00:00Z") },
{ _id: 2, item: "jkl", date: ISODate("2014-02-03T09:00:00Z") },
{ _id: 3, item: "xyz", date: ISODate("2014-02-03T09:05:00Z") },
{ _id: 4, item: "abc", date: ISODate("2014-02-15T08:00:00Z") }
]);
// 按日期分组统计唯一商品
db.sales.aggregate([
{
$group: {
_id: {
day: { $dayOfYear: "$date" },
year: { $year: "$date" }
},
itemsSold: { $addToSet: "$item" }
}
}
]);
9. 变量操作符 ($let)
// 插入数据
db.sales.insertMany([
{ _id: 1, price: 10, tax: 0.50, applyDiscount: true },
{ _id: 2, price: 10, tax: 0.25, applyDiscount: false }
]);
// 使用变量计算最终价格
db.sales.aggregate([
{
$project: {
finalTotal: {
$let: {
vars: {
total: { $add: ["$price", "$tax"] },
discounted: { $cond: { if: "$applyDiscount", then: 0.9, else: 1 } }
},
in: { $multiply: ["$$total", "$$discounted"] }
}
}
}
}
]);
关键说明:
- 字段修正:所有
-id
已修正为_id
- 数据类型:
- 日期使用
ISODate()
- 整数使用
NumberInt()
- 日期使用
- 操作符注意:
$arrayElemAt
:索引从0开始,-1表示最后一个元素$cond
:三元运算符(条件 ? 值1 : 值2)$let
:先定义变量再使用($$变量名
)
- 执行顺序:
1. 创建集合 → 2. 插入数据 → 3. 执行聚合管道
- 版本要求:
- 按位操作符需要 MongoDB 6.3+
- 窗口函数需要 MongoDB 5.0+
建议逐段复制执行,每次执行前确保集合存在且数据格式正确。遇到语法错误时,检查括号闭合和逗号使用。
$mergeObjects 与集合表达式
场景说明
我们有两个集合:orders
(订单)和items
(商品)。我们需要将这两个集合的数据按照商品编号(item)进行关联,得到包含订单信息和商品库存信息的完整文档。
准备数据
// 创建orders集合并插入数据
db.orders.insertMany([
{ "_id": 1, "item": "abc", "price": 12, "ordered": 2 },
{ "_id": 2, "item": "jkl", "price": 20, "ordered": 1 }
])
// 创建items集合并插入数据
db.items.insertMany([
{ "_id": 1, "item": "abc", description: "product 1", "instock": 120 },
{ "_id": 2, "item": "def", description: "product 2", "instock": 80 },
{ "_id": 3, "item": "jkl", description: "product 3", "instock": 60 }
])
执行$lookup
聚合操作
我们分三次执行,以便更好理解命令参数
- 左连接操作(orders)
db.orders.aggregate([
{
$lookup: {
from: "items",
localField: "item", // orders
foreignField: "item", // items
as: "fromItems"
}
}
])
- 可以看到orders的左连接合并结果是以我们提供的
as: "fromItems"
为字段的数组
- 我们需要把数组提出来,合并到根文档上,让两表各自所需的字段合在一起
db.orders.aggregate([
{
$lookup: {
from: "items",
localField: "item",
foreignField: "item",
as: "fromItems"
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
{ $arrayElemAt: ["$fromItems", 0]},
"$$ROOT"
]
}
}
}
])
- 接下来就是隐藏fromItems数组
db.orders.aggregate([
{
$lookup: {
from: "items",
localField: "item",
foreignField: "item",
as: "fromItems"
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
{ $arrayElemAt: ["$fromItems", 0]},
"$$ROOT"
]
}
}
},
{
$project: { fromItems: 0}
}
])