如何用MongoDB聚合合并基础记录与两层编辑数据并支持查询
MongoDB聚合实现基础数据与多角色编辑数据的合并查询
问题背景
我有一个存储基础图书记录的集合(示例数据如下),管理员和普通用户的编辑内容单独存在另一个集合中。需要编写MongoDB聚合操作,先合并基础数据与管理员编辑内容,再用用户编辑内容覆盖,同时保留编辑时新增的字段(比如示例中的frontOfStore),并且支持对这些新增字段进行查询。
基础记录集合(baseRecords)
[ { "_id": "one", "name": "The Enchanted River", "description": "A mystical journey along a forgotten river that holds secrets of a lost civilization.", "paperCopy": true, "digitalCopy": true, "bestSeller": true, "isDiscounted": false, "discountPercentage": 0.0 }, { "_id": "two", "name": "Galactic Odyssey", "description": "An epic space adventure exploring distant galaxies and encountering alien civilizations.", "paperCopy": true, "digitalCopy": false, "bestSeller": true, "isDiscounted": false, "discountPercentage": 5.57 }, { "_id": "three", "name": "The Last Heir", "description": "A gripping tale of a young prince fighting to reclaim his throne against all odds.", "paperCopy": true, "digitalCopy": true, "bestSeller": true, "isDiscounted": false, "discountPercentage": 27.1 }, { "_id": "four", "name": "Quantum Dreams", "description": "A scientist's groundbreaking discovery challenges the very fabric of reality.", "paperCopy": true, "digitalCopy": true, "bestSeller": true, "isDiscounted": true, "discountPercentage": 22.85 }, { "_id": "five", "name": "The Forgotten Garden", "description": "An old gardener unravels the secrets of a mysterious estate with a tragic past.", "paperCopy": false, "digitalCopy": true, "bestSeller": false, "isDiscounted": false, "discountPercentage": 0.0 } ]
编辑记录集合(edits)
[ { "_id": "one", "user": "admin", "patch": { "bestSeller": false } }, { "_id": "one", "user": "user1", "patch": { "bestSeller": true, "isDiscounted": true, "discountPercentage": 99, "frontOfStore": true } } ]
解决方案
聚合操作代码
db.baseRecords.aggregate([ // 关联编辑集合,获取当前记录的所有编辑历史 { $lookup: { from: "edits", localField: "_id", foreignField: "_id", as: "editHistory" } }, // 筛选出管理员和目标用户的编辑内容(用户编辑优先级更高) { $addFields: { adminPatch: { $first: { $filter: { input: "$editHistory", cond: { $eq: ["$$this.user", "admin"] } } } }, userPatch: { $first: { $filter: { input: "$editHistory", cond: { $eq: ["$$this.user", "user1"] } // 替换为当前查询的用户ID } } } } }, // 按顺序合并数据:基础数据 → 管理员编辑覆盖 → 用户编辑覆盖 { $replaceRoot: { newRoot: { $mergeObjects: [ "$$ROOT", "$adminPatch.patch", "$userPatch.patch" ] } } }, // 清理临时字段,让结果更整洁 { $project: { editHistory: 0, adminPatch: 0, userPatch: 0 } } ])
关键步骤说明
- 关联编辑数据:通过
$lookup把基础记录和对应的编辑历史关联起来,方便后续处理。 - 拆分编辑角色:用
$filter分别提取管理员和目标用户的编辑内容,确保同一字段下用户编辑会覆盖管理员的(因为后面合并时用户补丁在管理员补丁之后)。 - 合并与覆盖:
$mergeObjects会按顺序合并对象,后面的对象字段会覆盖前面的同名字段,同时保留编辑时新增的字段(比如示例中的frontOfStore会直接加入最终结果)。 - 动态适配用户:把代码中的
user1替换为当前登录用户的ID,就能实现针对不同用户展示其专属编辑后的内容。
新增字段查询示例
如果要查询frontOfStore为true的记录,只需在聚合末尾添加$match阶段:
{ $match: { frontOfStore: true } }
内容的提问来源于stack exchange,提问作者Don P
相关产品推荐
相关产品推荐

