You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用MongoDB Query查询特定字段值变化的文档列表?

如何用MongoDB查询特定字段值与前序文档不同的文档

可以直接用MongoDB的聚合管道实现,不需要通过脚本迭代。针对你给出的示例场景,以下是具体解决方案:

前提说明

必须给文档指定明确的排序规则(比如按_id、创建时间字段等),因为"前序文档"的定义依赖固定顺序,示例中的#1到#5默认按_id升序排列。


方案一:使用MongoDB 5.0+的$setWindowFields(推荐,高效简洁)

MongoDB 5.0及以上版本支持窗口函数,用$lag操作符可直接获取前一个文档的字段值,再对比筛选:

db.collection.aggregate([
  // 1. 按固定顺序排序(这里用_id升序对应示例的#1到#5)
  { $sort: { _id: 1 } },
  // 2. 用窗口函数获取前一个文档的name字段
  {
    $setWindowFields: {
      partitionBy: null, // 不分区,整个集合作为一个窗口
      sortBy: { _id: 1 },
      output: {
        prevName: {
          $lag: "$name", // 取前一个文档的name值
          offset: 1,
          default: null // 第一个文档没有前序,设为null
        }
      }
    }
  },
  // 3. 筛选符合要求的文档
  {
    $match: {
      $or: [
        // 匹配第二个及以后、且与前序name相同的文档(对应示例#2)
        { $and: [{ prevName: "$name" }, { prevName: { $ne: null } }] },
        // 匹配与前序name不同的文档(对应示例#3、#4)
        { $expr: { $ne: ["$name", "$prevName"] } }
      ]
    }
  },
  // 移除辅助字段,返回原始文档结构
  { $unset: "prevName" }
])

逻辑解释

  • $sort确保文档按固定顺序排列,这是确定"前序文档"的基础
  • $setWindowFields的$lag操作符会为每个文档添加prevName字段,存储前一个文档的name值
  • $match的条件覆盖两种情况:
    1. 非第一个文档,且当前name和前序相同(对应示例中的#2)
    2. 当前name和前序不同(对应示例中的#3、#4)
  • 最后用$unset移除辅助字段prevName,返回和原始文档一致的结构

方案二:兼容MongoDB 5.0以下版本

如果你的MongoDB版本低于5.0,可以用聚合管道的$group+$unwind组合实现:

db.collection.aggregate([
  // 1. 按固定顺序排序
  { $sort: { _id: 1 } },
  // 2. 将所有文档存入一个数组
  { $group: { _id: null, docs: { $push: "$$ROOT" } } },
  // 3. 展开数组并记录每个文档的位置索引
  { $unwind: { path: "$docs", includeArrayIndex: "position" } },
  // 4. 根据位置索引获取前一个文档
  {
    $addFields: {
      prevDoc: {
        $arrayElemAt: ["$docs", { $subtract: ["$position", 1] }]
      }
    }
  },
  // 5. 筛选符合要求的文档
  {
    $match: {
      $or: [
        { $and: [{ "prevDoc.name": "$docs.name" }, { position: { $gt: 0 } }] },
        { $expr: { $ne: ["$docs.name", "$prevDoc.name"] } }
      ]
    }
  },
  // 6. 恢复原始文档结构
  { $replaceRoot: { newRoot: "$docs" } }
])

逻辑解释

  • 先把排序后的所有文档存入一个数组,再展开每个文档并记录位置
  • 通过位置索引计算出前一个文档的位置,用$arrayElemAt取出前序文档
  • 后续的筛选逻辑和方案一一致,最后用$replaceRoot恢复原始文档结构

内容的提问来源于stack exchange,提问作者Hesoyam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 14:52:47