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

MongoDB查询:如何仅返回嵌套文档中符合条件的子文档?

问题描述

我有一个包含运动员ID、赛季以及运动员参与的各类赛事和成绩列表的数据集,结构如下:

[
  {
    'id':'123',
    'season':'2019',
    'event_type1':[
      {'Date':'20 Oct 2019', 'Location':'somewhere1','result':'182'},
      {'Date':'20 Oct 2019', 'Location':'somewhere2','result':'184'}
    ], 
    'event_type2':[
      {'Date':'20 Oct 2019', 'Location':'somewhere1','result':'182'},
      {'Date':'20 Oct 2019', 'Location':'somewhere2','result':'184'}
    ]
  }
]

目前我能通过以下查询语句,找出所有event_type1中至少存在一个Location为somewhere1的文档:

query = {
    '$and': [
        {'season': 2019},
        {'event_type1':{ '$elemMatch' : {'Location':'somewhere1'}}}
    ]
}
db.col.find(query)

但我希望仅返回event_type1中Location为somewhere1的子文档,而不是包含符合条件子文档的整个父文档。目前只能通过遍历返回的字典来处理,未找到更优方法。

补充信息:我的场景中event_type名称包含空格,且不同运动员的event_type不尽相同,尝试$unwind方法未成功。


解决方案

可以直接检索出目标子文档,根据你的场景(动态event_type名称、带空格),通过MongoDB聚合管道实现,分两种情况说明:

1. 针对已知名称的event_type(含带空格的名称)

如果明确要查询的event_type名称,用$project配合$filter提取数组中符合条件的元素,再通过$unwind展开、$replaceRoot将子文档设为根返回:

db.col.aggregate([
  // 筛选赛季符合条件且目标event_type存在匹配子文档的父文档
  {
    $match: {
      'season': '2019',
      'event_type1.Location': 'somewhere1'
    }
  },
  // 过滤event_type1数组,仅保留Location为somewhere1的元素
  {
    $project: {
      matched_events: {
        $filter: {
          input: '$event_type1',
          cond: { $eq: ['$$this.Location', 'somewhere1'] }
        }
      }
    }
  },
  // 展开匹配到的子文档数组,每个元素成为单独文档
  { $unwind: '$matched_events' },
  // 将子文档设为根文档,直接返回目标内容
  { $replaceRoot: { newRoot: '$matched_events' } }
])

如果event_type名称带空格(如Track and Field),只需用引号包裹字段名:'Track and Field.Location',$filter的input改为'$Track and Field'即可。

2. 针对未知/动态的event_type名称

如果不同运动员的event_type各不相同,无法提前指定字段名,用$objectToArray将文档转为键值对数组,统一遍历处理所有event_type字段:

db.col.aggregate([
  // 筛选赛季符合条件的文档
  { $match: { 'season': '2019' } },
  // 将文档转为键值对数组,方便遍历所有字段
  { $project: { events: { $objectToArray: '$$ROOT' } } },
  // 展开所有键值对
  { $unwind: '$events' },
  // 筛选出值为数组的字段(即各类event_type),且数组中存在目标子文档
  {
    $match: {
      'events.v': { $type: 'array' },
      'events.v.Location': 'somewhere1'
    }
  },
  // 过滤每个event_type数组中的目标子文档
  {
    $project: {
      matched_events: {
        $filter: {
          input: '$events.v',
          cond: { $eq: ['$$this.Location', 'somewhere1'] }
        }
      }
    }
  },
  // 展开匹配到的子文档数组
  { $unwind: '$matched_events' },
  // 返回子文档作为根文档
  { $replaceRoot: { newRoot: '$matched_events' } }
])

这个方法会自动遍历文档中所有数组类型的字段,找出所有包含Location: 'somewhere1'的子文档并返回。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 22:06:26