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

MongoDB中如何匹配数组内指定menu_id并返回对应数组元素

MongoDB查询:提取匹配指定menu_id的子文档

嘿,我懂你的需求了——你想要从tbl_roles集合里,精准取出menu数组中匹配指定menu_id的那个子文档,而不是返回整个角色文档对吧?你当前的查询只是找到了包含目标menu_id的角色文档,但没有过滤掉数组里的其他元素,这就是为啥得不到你想要的结果。

先回顾下你的样本数据:

[
  {
    "_id": ObjectId("611532b19c6e77ad0fd50c1c"),
    "status": true,
    "role_name": "DEVELOPER",
    "descr": "DEVELOPER",
    "menu": [
      {
        "permissions": [
          ObjectId("60eeabbc9ca3e3a4f03ff5ee"),
          ObjectId("611125cad17b0c71595298d4"),
          ObjectId("6113e8d69c6e77ad0fd50c08"),
          ObjectId("61279df3f544f6c2db48b92d"),
          ObjectId("612a3f061a1fcead8871e821")
        ],
        "_id": ObjectId("612a46c41a1fcead8871e83f"),
        "menu_id": ObjectId("611fe0b60734048a04812020")
      },
      {
        "permissions": [
          ObjectId("60eeabbc9ca3e3a4f03ff5ee"),
          ObjectId("611125cad17b0c71595298d4"),
          ObjectId("6113e8d69c6e77ad0fd50c08"),
          ObjectId("61279df3f544f6c2db48b92d"),
          ObjectId("612a3f061a1fcead8871e821")
        ],
        "_id": ObjectId("612a46c41a1fcead8871e840"),
        "menu_id": ObjectId("611fee7e0734048a04812022")
      },
      {
        "permissions": [
          ObjectId("60eeabbc9ca3e3a4f03ff5ee"),
          ObjectId("611125cad17b0c71595298d4"),
          ObjectId("6113e8d69c6e77ad0fd50c08"),
          ObjectId("61279df3f544f6c2db48b92d"),
          ObjectId("612a3f061a1fcead8871e821")
        ],
        "_id": ObjectId("612a46c41a1fcead8871e841"),
        "menu_id": ObjectId("6128c64f9bd697e83dbe47b1")
      },
      {
        "permissions": [
          ObjectId("60eeabbc9ca3e3a4f03ff5ee"),
          ObjectId("611125cad17b0c71595298d4"),
          ObjectId("6113e8d69c6e77ad0fd50c08"),
          ObjectId("61279df3f544f6c2db48b92d"),
          ObjectId("612a3f061a1fcead8871e821")
        ],
        "_id": ObjectId("612a46c41a1fcead8871e842"),
        "menu_id": ObjectId("6128c5e19bd697e83dbe47ac")
      }
    ],
    "createdAt": ISODate("2021-08-12T14:39:45.505+0000"),
    "updatedAt": ISODate("2021-08-28T14:23:00.040+0000"),
    "__v": NumberInt(10)
  }
]

接下来给你两种解决方案,按需选择:

方法1:使用find配合$elemMatch投影(简单快速)

这个方法适合只需要从单个文档中提取第一个匹配的子文档的场景:

db.getCollection("tbl_roles").find(
  { "menu.menu_id": ObjectId("611fe0b60734048a04812020") },
  { "menu": { $elemMatch: { "menu_id": ObjectId("611fe0b60734048a04812020") } }, "_id": 0 }
)

解释:

  • 第一个参数是查询条件,筛选出包含目标menu_id的角色文档
  • 第二个参数是投影规则:用$elemMatch只保留menu数组中匹配指定menu_id的元素,_id: 0是移除根文档的_id字段

返回结果会是这样的格式(外层带menu字段):

{
  "menu": [
    {
      "permissions": [
        ObjectId("60eeabbc9ca3e3a4f03ff5ee"),
        ObjectId("611125cad17b0c71595298d4"),
        ObjectId("6113e8d69c6e77ad0fd50c08"),
        ObjectId("61279df3f544f6c2db48b92d"),
        ObjectId("612a3f061a1fcead8871e821")
      ],
      "_id": ObjectId("612a46c41a1fcead8871e83f"),
      "menu_id": ObjectId("611fe0b60734048a04812020")
    }
  ]
}

方法2:使用聚合管道(完全匹配你要的结果格式)

如果想直接得到子文档作为根结果,用聚合管道更灵活,适合多场景:

db.getCollection("tbl_roles").aggregate([
  // 第一步:筛选出包含目标menu_id的角色文档
  { $match: { "menu.menu_id": ObjectId("611fe0b60734048a04812020") } },
  // 第二步:将menu数组拆分为单个文档
  { $unwind: "$menu" },
  // 第三步:精准筛选出匹配目标menu_id的子文档
  { $match: { "menu.menu_id": ObjectId("611fe0b60734048a04812020") } },
  // 第四步:将子文档作为根文档返回
  { $replaceRoot: { newRoot: "$menu" } }
])

解释:

  • $match:先缩小范围,找到包含目标menu_id的角色文档
  • $unwind:把menu数组拆成独立的文档,每个文档对应一个菜单子项
  • 再次$match:精准提取出匹配目标menu_id的那个菜单子文档
  • $replaceRoot:将这个子文档提升为根文档,完全符合你想要的结果格式

这个查询返回的结果就是你期望的:

{
  "permissions" : [
    ObjectId("60eeabbc9ca3e3a4f03ff5ee"),
    ObjectId("611125cad17b0c71595298d4"),
    ObjectId("6113e8d69c6e77ad0fd50c08"),
    ObjectId("61279df3f544f6c2db48b92d"),
    ObjectId("612a3f061a1fcead8871e821")
  ],
  "_id" : ObjectId("612a46c41a1fcead8871e83f"),
  "menu_id" : ObjectId("611fe0b60734048a04812020")
}

如果你的集合中存在多个角色文档包含同一个menu_id,聚合管道会返回所有匹配的子文档,而find方法会每个角色文档返回一个匹配的子项(外层带menu字段),根据你的需求选择就行~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 08:23:45