如何在MongoDB中基于子文档实现按玩家权限的条件投影?
解决MongoDB基于用户ID过滤城市敏感字段的查询需求
原始文档结构
{ "map": { "cities": [ { "name": "City1", "x": 15, "y": 5, "owner": 1, "defense": 6, "income": 35 }, { "name": "City2", "x": 12, "y": 14, "owner": 0, "defense": 4, "income": 16 }, { "name": "City3", "x": 6, "y": 19, "owner": 2, "defense": 3, "income": 12 } ] }, "players": [ { "userid": "64d3ebfb42fb5b118b928f5c", "faction": 1 }, { "userid": "636f89f0d4666b666237cec8", "faction": 2 } ] }
查询需求
- 仅接收
userid作为输入,返回过滤后的地图数据 - 核心规则:
- 仅当玩家所属派系(
players.faction)与城市所属派系(map.cities.owner)匹配时,显示该城市的defense和income实际值 - 非玩家所属城市不显示
defense和income(或默认设为0)
- 仅当玩家所属派系(
示例返回结果
查询userid="64d3ebfb42fb5b118b928f5c"时
{ "map": { "cities": [ { "name": "City1", "x": 15, "y": 5, "owner": 1, "defense": 6, "income": 35 }, { "name": "City2", "x": 12, "y": 14, "owner": 0 }, { "name": "City3", "x": 6, "y": 19, "owner": 2 } ] } }
查询userid="636f89f0d4666b666237cec8"时
{ "map": { "cities": [ { "name": "City1", "x": 15, "y": 5, "owner": 1 }, { "name": "City2", "x": 12, "y": 14, "owner": 0 }, { "name": "City3", "x": 6, "y": 19, "owner": 2, "defense": 3, "income": 12 } ] } }
解决方案:MongoDB聚合查询
使用聚合管道实现字段过滤,以下是完整查询语句(将<输入的userid>替换为实际参数):
db.collection.aggregate([ // 1. 匹配包含目标用户的文档 { $match: { "players.userid": "<输入的userid>" } }, // 2. 提取当前用户的派系ID,存入临时字段 { $addFields: { currentFaction: { $arrayElemAt: [ { $filter: { input: "$players", cond: { $eq: ["$$this.userid", "<输入的userid>"] } } }, 0 ] } } }, // 3. 遍历城市数组,按规则过滤敏感字段 { $addFields: { "map.cities": { $map: { input: "$map.cities", as: "city", in: { name: "$$city.name", x: "$$city.x", y: "$$city.y", owner: "$$city.owner", // 仅匹配派系时保留defense,否则移除字段(或改为0) defense: { $cond: { if: { $eq: ["$$city.owner", "$currentFaction.faction"] }, then: "$$city.defense", else: "$$REMOVE" } }, // 仅匹配派系时保留income,否则移除字段(或改为0) income: { $cond: { if: { $eq: ["$$city.owner", "$currentFaction.faction"] }, then: "$$city.income", else: "$$REMOVE" } } } } } } }, // 4. 只返回最终需要的map字段 { $project: { map: 1, _id: 0 } } ])
代码说明
$match:快速定位到包含目标用户的游戏文档$filter + $arrayElemAt:从players数组中提取当前用户的派系信息,避免后续重复遍历$map + $cond:逐个处理城市数据,通过条件判断控制敏感字段的显示逻辑,若需要默认值0,将$$REMOVE替换为0即可$project:清理返回结果,只保留所需的map字段
内容的提问来源于stack exchange,提问作者scratch
相关产品推荐
相关产品推荐

