如何用单条MongoDB查询从三个集合获取指定格式的数据?
MongoDB Aggregation Query to Join Three Collections and Project Custom Fields
要实现你需要的结果,我们可以用MongoDB的聚合管道,通过多次$lookup关联集合,再通过数组操作匹配问题和对应的答案,最终投影出目标格式的数据。以下是完整的查询语句:
db.FormSubmissions.aggregate([ // 关联FormAnswers,获取当前提交对应的答案文档 { $lookup: { from: "FormAnswers", localField: "_id", foreignField: "FormSubmissionId", as: "submissionAnswers" } }, // 展开答案数组(每个提交对应一个答案文档,展开后便于后续处理) { $unwind: "$submissionAnswers" }, // 关联FormQuestions,获取当前表单版本的问题定义 { $lookup: { from: "FormQuestions", let: { formId: "$FormId", formVersionId: "$FormVersionId", languageId: "$LanguageId" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: ["$FormId", "$$formId"] }, { $eq: ["$FormVersionId", "$$formVersionId"] }, { $eq: ["$LanguageId", "$$languageId"] } ] } } } ], as: "formQuestions" } }, // 展开问题数组(每个表单版本对应一个问题文档) { $unwind: "$formQuestions" }, // 投影出需要的字段,匹配问题对应的答案值 { $project: { _id: 1, LanguageId: 1, FormId: 1, FormVersionId: 1, SubmittedOn: 1, EmployeeId: 1, // 获取Name对应的答案 Name: { $let: { vars: { nameQuestion: { $arrayElemAt: [ { $filter: { input: "$formQuestions.Questions", cond: { $eq: ["$$this.Question", "Name"] } } }, 0 ] } }, in: { $arrayElemAt: [ { $filter: { input: "$submissionAnswers.Answers", cond: { $eq: ["$$this.FormQuestionId", "$$nameQuestion._id"] } } }, 0 ].Value } } }, // 获取Type对应的答案 Type: { $let: { vars: { typeQuestion: { $arrayElemAt: [ { $filter: { input: "$formQuestions.Questions", cond: { $eq: ["$$this.Question", "Type"] } } }, 0 ] } }, in: { $arrayElemAt: [ { $filter: { input: "$submissionAnswers.Answers", cond: { $eq: ["$$this.FormQuestionId", "$$typeQuestion._id"] } } }, 0 ].Value } } } } } ])
关键步骤说明:
- 第一次
$lookup:将FormSubmissions与FormAnswers通过_id和FormSubmissionId关联,拿到当前提交的所有答案。 $unwind:展开答案数组,因为每个提交对应唯一的答案文档,展开后可以直接处理单个答案集合。- 第二次
$lookup:通过表单ID、版本ID和语言ID关联FormQuestions,获取该表单版本的所有问题定义,确保我们能匹配到正确的问题名称对应的答案。 $unwind:展开问题文档数组,同样因为每个表单版本对应唯一的问题文档。$project:使用$filter和$arrayElemAt从问题数组中找到Question为"Name"和"Type"的项,再从答案数组中匹配对应的FormQuestionId,最终提取出答案的Value作为新增字段。
这个查询会返回你需要的格式数据,每个提交记录都包含原有的字段,加上对应的Name和Type值。
内容的提问来源于stack exchange,提问作者Pankaj Kamadiya
相关产品推荐
相关产品推荐

