如何查询文档中对象的所有子对象?

How to query all children of an object within a document?

以三个文档为例

[
  {
    _id: '/players/c/cruzne02.shtml',
    url: '/players/c/cruzne02.shtml',
    name: 'Nelson Cruz',
    image: 'https://www.baseball-reference.com/req/202108020/images/headshots/f/fea2f131_mlbam.jpg',
    teams: {
      MIL: [ 2005 ],
      TEX: [
        2006, 2007, 2007, 2008,
        2008, 2009, 2009, 2010,
        2010, 2011, 2011, 2012,
        2012, 2013, 2013
      ],
      BAL: [ 2014 ],
      SEA: [
        2015, 2016,
        2016, 2017,
        2017, 2018,
        2018
      ],
      MIN: [ 2019, 2020, 2020, 2021, 2021 ],
      TBR: [ 2021 ]
    }
  },
  {
    _id: '/players/b/berrijo01.shtml',
    url: '/players/b/berrijo01.shtml',
    name: 'Jose Berrios',
    image: 'https://www.baseball-reference.com/req/202108020/images/headshots/d/d94db113_mlbam.jpg',
    teams: {
      MIN: [
        2016, 2017, 2017,
        2018, 2018, 2019,
        2019, 2020, 2020,
        2021, 2021
      ],
      TOR: [ 2021 ]
    }
  },
  {
    _id: '/players/m/mauerjo01.shtml',
    url: '/players/m/mauerjo01.shtml',
    name: 'Joe Mauer',
    image: 'https://www.baseball-reference.com/req/202108020/images/headshots/4/43c69595_mlbam.jpg',
    teams: {
      MIN: [
        2004, 2005, 2005, 2006, 2006,
        2007, 2007, 2008, 2008, 2009,
        2009, 2010, 2010, 2011, 2011,
        2012, 2012, 2013, 2013, 2014,
        2014, 2015, 2015, 2016, 2016,
        2017, 2017, 2018, 2018
      ]
    }
  }
]

假设我想获得在 2010 年参加比赛的两名球员,这将是第一个和第三个文件。当我被提供了我正在寻找球员的年份时,我该如何写这个发现。我尝试寻找通配符和查询对象所有子项的方法,但在这种情况下,键并不总是匹配。

与 2010 年一样,第一个文档为 TEX:2010,第三个文档为 MIN:2010。谁能帮帮我?

查询

  • 将团队转换为数组以拥有

    [["MIL", [2005] ["TEX": [2006,2007,...]] ...]
    
  • reduce 从 false 开始,并检查 2010 是否是任何这些数组的第二个成员中的成员 [2005],[2006,2007,...] 等 如果它至少是其中一个数组的成员,则 reduce returns 为真,文档通过匹配阶段

  • 适用于 1 个比赛阶段,而且速度很快

*你可以避免使用 $$result$$t 但我用它们来给 reduce 参数的名称,您可以删除它们。

Test code here

db.collection.aggregate([
  {
    "$match": {
      "$expr": {
        "$reduce": {
          "input": {
            "$map": {
              "input": {
                "$objectToArray": "$teams"
              },
              "as": "m",
              "in": [
                "$$m.k",
                "$$m.v"
              ]
            }
          },
          "initialValue": false,
          "in": {
            "$let": {
              "vars": {
                "result": "$$value",
                "t": "$$this"
              },
              "in": {
                "$cond": [
                  {
                    "$or": [
                      "$$result",
                      {
                        "$in": [
                          2010,
                          {
                            "$arrayElemAt": [
                              "$$t",
                              1
                            ]
                          }
                        ]
                      }
                    ]
                  },
                  true,
                  false
                ]
              }
            }
          }
        }
      }
    }
  }
])

Test code here

查询(与上面几乎相同,没有任何额外的变量等)

db.collection.aggregate([
  {
    $match: {
      $expr: {
        $reduce: {
          input: {
            $objectToArray: "$teams"
          },
          initialValue: false,
          in: {
            $cond: [
              {
                $or: [
                  "$$value",
                  {
                    $in: [
                      2010,
                      "$$this.v"
                    ]
                  }
                ]
              },
              true,
              false
            ]
          }
        }
      }
    }
  }
])