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

MongoDB多集合复杂聚合查询构建技术求助

MongoDB聚合查询方案:关联users与training_documents集合

看起来你是要处理用户培训数据的关联查询,我假设你最常见的需求是获取用户列表并关联其培训记录对应的文档详情,或者反过来获取培训文档对应的受训用户列表,下面分别给出具体实现:

场景1:获取用户及关联的培训文档详情

这个查询会把每个用户trainings数组里的document字段,关联到training_documents集合的完整文档信息:

db.users.aggregate([
  // 1. 先展开用户的trainings数组,让每个培训条目单独处理
  { $unwind: "$trainings" },
  // 2. 关联training_documents集合,匹配ObjectId对应的文档
  {
    $lookup: {
      from: "training_documents",
      localField: "trainings.document",
      foreignField: "_id",
      as: "trainings.document_info"
    }
  },
  // 3. 将拆分后的培训条目重新聚合回原用户下
  {
    $group: {
      _id: "$_id",
      // 这里替换为你实际需要保留的用户字段,比如姓名、邮箱等
      username: { $first: "$username" },
      email: { $first: "$email" },
      trainings: { $push: "$trainings" }
    }
  },
  // 4. 可选优化:把lookup返回的数组转为单个对象(因为每个document对应唯一文档)
  {
    $addFields: {
      trainings: {
        $map: {
          input: "$trainings",
          as: "item",
          in: {
            trainee: "$$item.trainee",
            document: "$$item.document",
            document_info: { $arrayElemAt: ["$$item.document_info", 0] }
          }
        }
      }
    }
  }
])

关键步骤说明:

  • $unwind:把嵌套的trainings数组拆分成独立文档,这样每个培训条目才能单独和training_documents做关联。
  • $lookup:相当于SQL的左连接,通过ObjectId匹配对应的培训文档,结果存在临时数组里。
  • $group:把拆分后的文档重新按用户ID聚合,恢复用户原有的结构,同时保留需要的用户字段。
  • $map + $arrayElemAt:因为$lookup返回的是数组,这里把它转为单个对象,让最终结构更简洁直观。

场景2:获取培训文档及对应的受训用户列表

如果你的需求是反向查询——查看每个培训文档有哪些用户参与,用这个查询:

db.training_documents.aggregate([
  // 关联users集合,匹配所有trainings.document等于当前文档ID的用户
  {
    $lookup: {
      from: "users",
      localField: "_id",
      foreignField: "trainings.document",
      as: "trainee_users"
    }
  },
  // 可选优化:只保留用户的关键信息,避免返回冗余数据
  {
    $addFields: {
      trainee_users: {
        $map: {
          input: "$trainee_users",
          as: "user",
          in: {
            user_id: "$$user._id",
            username: "$$user.username"
          }
        }
      }
    }
  }
])

注意事项:

  • 确保trainings.document和training_documents._id的类型都是ObjectId,如果是字符串格式的ObjectId,需要先用$toObjectId转换后再做匹配。
  • 可以根据实际业务需求调整字段,比如在$group或$map阶段添加/删除需要展示的字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:49:11