【MongoDB】多种聚合操作详解,案例分析

发布于:2025-08-20 ⋅ 阅读:(17) ⋅ 点赞:(0)

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"] }
        }
      }
    }
  }
]);

关键说明:

  1. 字段修正:所有 -id 已修正为 _id
  2. 数据类型
    • 日期使用 ISODate()
    • 整数使用 NumberInt()
  3. 操作符注意
    • $arrayElemAt:索引从0开始,-1表示最后一个元素
    • $cond:三元运算符(条件 ? 值1 : 值2)
    • $let:先定义变量再使用($$变量名
  4. 执行顺序
    1. 创建集合 → 2. 插入数据 → 3. 执行聚合管道
    
  5. 版本要求
    • 按位操作符需要 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}
  }
])

在这里插入图片描述



网站公告

今日签到

点亮在社区的每一天
去签到