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

MongoDB聚合查询:获取已匹配文档的itemId关联记录

问题:MongoDB聚合查询获取关联itemId的所有记录

集合Schema

const ContentSchema = new Schema({
    label: {
        type: String
    },
    itemId: {
        type: Schema.ObjectId,
        refPath: 'onModel'
    },
    formId: {
        type: Schema.ObjectId,
        refPath: 'onModel'
    },
    value: {
        type: Schema.Types.Mixed,
        index: "text"
    },
}, { timestamps: true, versionKey: false });

示例文档

{
  _id: ObjectId('647b1538c29a553ad6e8f316'),
  label: "Name",
  itemId: ObjectId('647b1538c29a553ad6e8f313'),
  formId: ObjectId('647b1538c29a553ad6e8f913'),
  value: "ABC"
},
{
  _id: ObjectId('647b1538c29a553ad6e8f416'),
  label: "Email",
  itemId: ObjectId('647b1538c29a553ad6e8f313'),
  formId: ObjectId('647b1538c29a553ad6e8f913'),
  value: "def@mail.com"
},
{
  _id: ObjectId('647b1538c29a553ad6e8f516'),
  label: "Name",
  itemId: ObjectId('647b1538c29a553ad6e8f320'),
  formId: ObjectId('647b1538c29a553ad6e8f913'),
  value: "MNO"
},
{
  _id: ObjectId('647b1538c29a553ad6e8f616'),
  label: "Email",
  itemId: ObjectId('647b1538c29a553ad6e8f320'),
  formId: ObjectId('647b1538c29a553ad6e8f913'),
  value: "xyz@mail.com"
}

需求与问题

我需要先查询formId为ObjectId('647b1538c29a553ad6e8f913')且value匹配"ABC"的文档,再获取该文档itemId对应的所有关联记录(期望返回2条文档)。

目前用以下聚合可以正确找到目标文档:

return await ContentModel.aggregate([
{
    $match: {
        $text: { $search: text },
        formId: new mongoose.Types.ObjectId(formId)
    }
}]

但尝试添加第二个$match阶段来筛选关联记录时无效:

return await ContentModel.aggregate([
{
    $match: {
        $text: { $search: text },
        formId: new mongoose.Types.ObjectId(formId)
    }
},
{
    $match: { itemId: "$itemId" }
}]

正确聚合写法

方法1:单聚合管道完成查询

利用$group收集目标itemId,再通过$lookup关联自身集合获取所有关联记录:

return await ContentModel.aggregate([
  // 1. 匹配到符合条件的目标文档
  {
    $match: {
      $text: { $search: text },
      formId: new mongoose.Types.ObjectId(formId)
    }
  },
  // 2. 收集所有匹配到的itemId(去重,避免重复查询)
  {
    $group: {
      _id: null,
      targetItemIds: { $addToSet: "$itemId" }
    }
  },
  // 3. 关联自身集合,获取对应itemId的所有记录
  {
    $lookup: {
      from: "contents", // 替换为你的集合实际名称
      localField: "targetItemIds",
      foreignField: "itemId",
      as: "relatedRecords"
    }
  },
  // 4. 展开嵌套的结果数组(可选,若需要直接返回每条文档而非数组)
  { $unwind: "$relatedRecords" },
  // 5. 将嵌套的文档转为根文档(可选)
  {
    $replaceRoot: { newRoot: "$relatedRecords" }
  }
]);

方法2:分两步查询(更简洁,适合单目标itemId场景)

先找到目标文档获取itemId,再直接查询该itemId的所有记录:

// 第一步:获取目标文档
const targetDoc = await ContentModel.findOne({
  $text: { $search: text },
  formId: new mongoose.Types.ObjectId(formId)
});

if (!targetDoc) {
  return [];
}

// 第二步:查询该itemId对应的所有记录
const relatedRecords = await ContentModel.find({
  itemId: targetDoc.itemId,
  formId: new mongoose.Types.ObjectId(formId) // 可选,若只需同formId下的记录可保留
});

return relatedRecords;

原写法无效原因

第二个$match阶段中itemId: "$itemId"的写法错误:$match阶段仅支持使用常量值作为查询条件,无法直接引用当前管道中文档的字段值。必须先通过$group或单独查询获取到目标itemId,再用该值进行匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 22:53:14