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

MongoDB:如何关联两集合获取指定条件文档($unionWith使用问题)

MongoDB跨集合聚合:筛选未完成最新测试的测试人员

我有两个集合BulkTests和Testers,需求是:

  • 获取BulkTests集合中testId的最大值
  • 找出Testers集合中testResponses字段的最大值(即lastTest)不等于该最大值的文档

尝试用$unionWith实现但没成功,当前聚合管道能正确获取lastTest,但match阶段的最大值是硬编码的,需要替换为BulkTests的最大testId。

集合结构

BulkTests

[
  {
    "_id": "65b82f4b13f7b6653662795d",
    "testDateTime": "2024-01-29T23:05:47.940+00:00",
    "testId": 19
  },
  {
    "_id": "65bac13912032ee4eae1d47f",
    "testDateTime": "2024-01-31T21:52:57.185+00:00",
    "testId": 20
  }
]

Testers

[
  {
    "_id": "65bc139856f9734f1d19285d",
    "name": "FooBar Bizzle",
    "testResponses": [7, 19]
  },
  {
    "_id": "65bc139856f9734f1d19285e",
    "name": "Baz Bar",
    "testResponses": [20]
  }
]

当前聚合管道(存在硬编码问题)

[
  {
    "$project": {
      "lastTest": {
        "$arrayElemAt": [
          "$testResponses",
          {
            "$indexOfArray": [
              "$testResponses",
              { "$max": "$testResponses" }
            ]
          }
        ]
      },
      "name": 1
    }
  },
  {
    "$match": {
      "lastTest": { "$ne": 20 } // 此处需要替换为BulkTests的最大testId
    }
  }
]

解决方案1:单聚合管道内完成(使用$lookup)

$unionWith适用于合并两个集合的结果,这里更适合用$lookup获取全局最大testId后再筛选,完整管道如下:

db.Testers.aggregate([
  // 1. 简化获取每个测试人员的lastTest
  {
    "$project": {
      "lastTest": { "$max": "$testResponses" },
      "name": 1,
      "_id": 1
    }
  },
  // 2. 关联BulkTests,获取全局最大testId
  {
    "$lookup": {
      "from": "BulkTests",
      "pipeline": [
        { "$group": { "_id": null, "maxTestId": { "$max": "$testId" } } }
      ],
      "as": "maxTestData"
    }
  },
  // 3. 展开关联结果数组
  { "$unwind": "$maxTestData" },
  // 4. 筛选lastTest不等于最大testId的文档
  {
    "$match": {
      "$expr": { "$ne": ["$lastTest", "$maxTestData.maxTestId"] }
    }
  },
  // 5. 整理输出字段(可选)
  {
    "$project": {
      "name": 1,
      "lastTest": 1,
      "_id": 1
    }
  }
])

关键说明:

  • 直接用$max取数组最大值,比原方法更简洁高效
  • 通过$lookup的子管道对BulkTests分组,一次性拿到全局最大testId
  • 用$expr实现聚合字段间的比较

解决方案2:先获取最大值再传入聚合(MongoDB 5.0+)

如果不需要严格在单管道内完成,这种方法更直观且性能更优:

// 1. 单独查询获取BulkTests的最大testId
const maxTestId = db.BulkTests.find().sort({ testId: -1 }).limit(1).toArray()[0].testId;

// 2. 传入变量执行聚合
db.Testers.aggregate([
  {
    "$project": {
      "lastTest": { "$max": "$testResponses" },
      "name": 1
    }
  },
  {
    "$match": {
      "lastTest": { "$ne": maxTestId }
    }
  }
])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 03:24:51