如何从MongoDB单文档生成多文档?附嵌套数组过滤条件
MongoDB 嵌套数组文档拆分与筛选查询
需求说明
- 针对包含
cars嵌套数组的MongoDB文档,需完成以下查询操作:- 筛选出
cars数组中存在status: "inprogress"且parent_company: true对象的组; - 每个组(按
parent_company_id划分)内至少有一个cars对象的model数组包含"v12"; - 将同一
parent_company_id对应的所有cars对象打包为独立文档,保留原文档的_id、name等顶层字段。
- 筛选出
数据库示例文档
{ "_id" : ObjectId("63a8808652f40e1d48a3d1d7"), "name" : "A", "description" : null, "cars" : [ { "id" : "63a8808c52f40e1d48a3d1da", "owner" : "John Doe", "purchase_date" : "2022-12-25", "status" : "inprogress", "parent_company" : true, "parent_company_id" : "63a8808c52f40e1d48a3d1da", "model" : [] }, { "id" : "63a880a552f40e1d48a3d1dc", "owner" : "John Doe 1", "purchase_date" : "2022-12-25", "parent_company" : false, "parent_company_id" : "63a8808c52f40e1d48a3d1da", "model" : ["v12"] }, { "id" : "63a880f752f40e1d48assddd", "owner" : "John Doe 1", "purchase_date" : "2022-12-25", "parent_company" : false, "parent_company_id" : "63a8808c52f40e1d48a3d1da", "model" : [] }, { "id" : "63a880f752f40e1d48a3d207", "owner" : "John Doe 11", "dt" : "2022-12-25", "status" : "inprogress", "parent_company" : true, "parent_company_id" : "63a880f752f40e1d48a3d207", "model" : ["v12"] }, { "id" : "63a880f752f40e1d48agfddd", "owner" : "John Doe 112", "dt" : "2022-12-25", "status" : "inprogress", "parent_company" : true, "parent_company_id" : "63a880f752f40e1d48agfddd", "model" : [] } ] }
预期查询结果
[ { "_id" : ObjectId("63a8808652f40e1d48a3d1d7"), "name" : "A", "description" : null, "cars" : [ { "id" : "63a8808c52f40e1d48a3d1da", "owner" : "John Doe", "purchase_date" : "2022-12-25", "status" : "inprogress", "parent_company" : true, "parent_company_id" : "63a8808c52f40e1d48a3d1da", "model" : [] }, { "id" : "63a880a552f40e1d48a3d1dc", "owner" : "John Doe 1", "purchase_date" : "2022-12-25", "parent_company" : false, "parent_company_id" : "63a8808c52f40e1d48a3d1da", "model" : ["v12"] }, { "id" : "63a880f752f40e1d48assddd", "owner" : "John Doe 1", "purchase_date" : "2022-12-25", "parent_company" : false, "parent_company_id" : "63a8808c52f40e1d48a3d1da", "model" : [] } ] }, { "_id" : ObjectId("63a8808652f40e1d48a3d1d7"), "name" : "A", "description" : null, "cars" : [ { "id" : "63a880f752f40e1d48a3d207", "owner" : "John Doe 11", "dt" : "2022-12-25", "status" : "inprogress", "parent_company" : true, "parent_company_id" : "63a880f752f40e1d48a3d207", "model" : ["v12"] } ] } ]
实现方案(聚合管道)
db.collection.aggregate([ // 展开cars数组,为每个元素生成独立中间文档 { $unwind: "$cars" }, // 按原文档ID和parent_company_id分组,收集组内车辆并标记是否含v12车型 { $group: { _id: { docId: "$_id", parentCompanyId: "$cars.parent_company_id" }, name: { $first: "$name" }, description: { $first: "$description" }, carsGroup: { $push: "$cars" }, hasV12: { $max: { $in: ["v12", "$cars.model"] } } } }, // 筛选符合条件的分组:存在指定父公司车辆,且组内有v12车型 { $match: { $and: [ { "carsGroup": { $elemMatch: { parent_company: true, status: "inprogress" } } }, { hasV12: true } ] } }, // 调整输出结构,恢复原文档顶层字段 { $project: { _id: "$_id.docId", name: 1, description: 1, cars: "$carsGroup" } } ])
管道阶段说明
- $unwind:将
cars数组拆分为单个元素的文档,为后续分组操作提供基础。 - $group:以原文档ID和
parent_company_id作为分组键,聚合同一组的所有车辆数据;同时通过$in判断单辆车是否含v12车型,再用$max确保只要组内有一辆符合就标记hasV12为true。 - $match:过滤掉不符合要求的分组:必须存在
parent_company=true且status=inprogress的车辆,同时组内要有v12车型。 - $project:重组文档结构,将分组后的车辆数组重命名为
cars,并保留原文档的_id、name等字段,与预期结果格式一致。
内容的提问来源于stack exchange,提问作者BlackWooDZZ
相关产品推荐
相关产品推荐

