Mongodb 多级嵌入式阵列中的匹配项

Mongodb 多级嵌入式阵列中的匹配项,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我使用以下代表体育>类别>锦标赛的集合 { "_id" : ObjectId("597846358bbbc4440895f2e8"), "Name" : [ { "k" : "en-US", "v" : "Soccer" }, { "k" : "fr-FR", "v" : "Football" } ], "Categories" : [ { "Name" : [

我使用以下代表体育>类别>锦标赛的集合

{
    "_id" : ObjectId("597846358bbbc4440895f2e8"),
    "Name" : [ 
        { "k" : "en-US", "v" : "Soccer" }, 
        { "k" : "fr-FR", "v" : "Football" }
    ],
    "Categories" : [ 
        {
            "Name" : [ 
                { "k" : "en-US", "v" : "France" }, 
                { "k" : "fr-FR", "v" : "France" }
            ],
            "Tournaments" : [ 
                {
                    "Name" : [ 
                        { "k" : "en-US", "v" : "Ligue 1" }, 
                        { "k" : "fr-FR", "v" : "Ligue 1" }
                    ],
                }, 
                {
                    "Name" : [ 
                        { "k" : "en-US", "v" : "Ligue 2" }, 
                        { "k" : "fr-FR", "v" : "Ligue 2" }
                    ],
                }
            ]
        }, 
        {
            "Name" : [ 
                { "k" : "en-US", "v" : "England" }, 
                { "k" : "fr-FR", "v" : "Angleterre" }
            ],
            "Tournaments" : [ 
                {
                    "Name" : [ 
                        { "k" : "en-US", "v" : "Premier League" }, 
                        { "k" : "fr-FR", "v" : "Premier League" }
                    ],
                }, 
                {
                    "Name" : [ 
                        { "k" : "en-US", "v" : "Championship" }, 
                        { "k" : "fr-FR", "v" : "Championnat" }
                    ],
                }
            ]
        }, 
    ]
}
我想使用类别名称和锦标赛名称查询集合。我已成功地将“$elemMatch”与以下代码一起使用:

db.getCollection('Sport').find({
    Categories: {
        $elemMatch: {
            Name: {
                $elemMatch: { v: "France" }
            },
            Tournaments: {
                $elemMatch: {
                    Name: {
                        $elemMatch: { v: "Ligue 1" }
                    }
                }
            }
        }
    } },
    { "Categories.$": 1, Name: 1 })
但是,我不能只接收类别对象中的匹配锦标赛。 使用这个问题的答案:,我构建了一个聚合:

db.getCollection('Sport').aggregate([{
            "$match": {
                "Categories": {
                    "$elemMatch": {
                        "Name": {
                            "$elemMatch": {
                                "v": "France"
                            }
                        },
                        "Tournaments": {
                            "$elemMatch": {
                                "Name": {
                                    "$elemMatch": {
                                        "v": "Ligue 1"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }, {
            "$addFields": {
                "Categories": {
                    "$filter": {
                        "input": {
                            "$map": {
                                "input": "$Categories",
                                "as": "category",
                                "in": {
                                    "Tournaments": {
                                        "$filter": {
                                            "input": "$$category.Tournaments",
                                            "as": "tournament",
                                            "cond": {
                                                // stuck here
                                            }
                                        }
                                    }
                                }
                            }
                        },
                        "as": "category",
                        "cond": {
                            // stuck here
                        }
                    }
                }
            }
        }
    ])
我试图使用一个条件,但当我在“Name”属性上使用$anyElementTrue然后$map时,MongoDB无法识别(使用未定义的变量:)$$KEEP和$$PRUNE()


我的问题:如何检查名称集合是否包含我的字符串?

我更惊讶的是,在您引用的答案中,我没有像这样“强烈建议您不要嵌套数组”。在MongoDB的下一个版本发布之前,以这种方式进行嵌套是不可能进行原子更新的,而且众所周知,它们很难查询

对于这种特殊情况,您可以执行以下操作:

db.getCollection('Sport').aggregate([
  { "$match": {
    "Categories": {
      "$elemMatch": {
        "Name.v": "France",
        "Tournaments.Name.v": "Ligue 1"    
      }
    }    
  }},
  { "$addFields": {
    "Categories": {
      "$filter": {
        "input": {
          "$map": {
            "input": "$Categories",
            "as": "c",
            "in": {
              "Name": {
                "$filter": {
                  "input": "$$c.Name",
                  "as": "n",
                  "cond": { "$eq": [ "$$n.v", "France" ] }
                }    
              },
              "Tournaments": {
                "$filter": {
                  "input": {
                    "$map": {
                      "input": "$$c.Tournaments",
                      "as": "t",
                      "in": {
                        "Name": {
                          "$filter": {
                            "input": "$$t.Name",
                            "as": "n",
                            "cond": { 
                              "$eq": [ "$$n.v", "Ligue 1" ]
                            }
                          }
                        }        
                      }
                    }
                  },
                  "as": "t",
                  "cond": {
                    "$ne": [{ "$size": "$$t.Name" }, 0]
                  }
                }
              }
            }
          }
        },
        "as": "c",
        "cond": {
          "$and": [
            { "$ne": [{ "$size": "$$c.Name" },0] },
            { "$ne": [{ "$size": "$$c.Tournaments" },0] }
          ]
        }
      } 
    }  
  }}
])
返回结果:

/* 1 */
{
    "_id" : ObjectId("597846358bbbc4440895f2e8"),
    "Name" : [ 
        {
            "k" : "en-US",
            "v" : "Soccer"
        }, 
        {
            "k" : "fr-FR",
            "v" : "Football"
        }
    ],
    "Categories" : [ 
        {
            "Name" : [ 
                {
                    "k" : "en-US",
                    "v" : "France"
                }, 
                {
                    "k" : "fr-FR",
                    "v" : "France"
                }
            ],
            "Tournaments" : [ 
                {
                    "Name" : [ 
                        {
                            "k" : "en-US",
                            "v" : "Ligue 1"
                        }, 
                        {
                            "k" : "fr-FR",
                            "v" : "Ligue 1"
                        }
                    ]
                }
            ]
        }
    ]
}
关键是每个数组都需要一个数组,而在外部级别,由于对包含的数组执行“内部”操作,您要寻找的不是
0

由于“内部”数组的内容会因此发生变化,“外部”数组需要一个数组来返回“已更改”的元素

因此,在结构方面,“Categories”需要一个元素,因为它有内部元素。“内部”
“锦标赛”
也因为同样的原因需要一个。一直到最终属性所需的每个数组,以及每个带条件的包装数组

这是通用逻辑模式,它通过对每个嵌套级别重复该模式来工作。尽管如此,这还是相当可怕的。这就是为什么你真的应该不惜一切代价避免像这样的“筑巢”。增加的复杂性几乎总是超过任何可感知的收益

我还应该注意到您有点过火了,您实际上只需要在
“Categories”
数组级别使用它,因为这是它的元素唯一需要满足多个条件的东西

子元素可以使用普通元素,因为它们只是各自数组中的“奇异”条件。因此,这确实在某种程度上减少了简洁的语法,并且仍然完全匹配相同的文档


我更惊讶的是,在您引用的答案中,我没有像这样“强烈建议您不要嵌套数组”。在MongoDB的下一个版本发布之前,以这种方式进行嵌套是不可能进行原子更新的,而且众所周知,它们很难查询

对于这种特殊情况,您可以执行以下操作:

db.getCollection('Sport').aggregate([
  { "$match": {
    "Categories": {
      "$elemMatch": {
        "Name.v": "France",
        "Tournaments.Name.v": "Ligue 1"    
      }
    }    
  }},
  { "$addFields": {
    "Categories": {
      "$filter": {
        "input": {
          "$map": {
            "input": "$Categories",
            "as": "c",
            "in": {
              "Name": {
                "$filter": {
                  "input": "$$c.Name",
                  "as": "n",
                  "cond": { "$eq": [ "$$n.v", "France" ] }
                }    
              },
              "Tournaments": {
                "$filter": {
                  "input": {
                    "$map": {
                      "input": "$$c.Tournaments",
                      "as": "t",
                      "in": {
                        "Name": {
                          "$filter": {
                            "input": "$$t.Name",
                            "as": "n",
                            "cond": { 
                              "$eq": [ "$$n.v", "Ligue 1" ]
                            }
                          }
                        }        
                      }
                    }
                  },
                  "as": "t",
                  "cond": {
                    "$ne": [{ "$size": "$$t.Name" }, 0]
                  }
                }
              }
            }
          }
        },
        "as": "c",
        "cond": {
          "$and": [
            { "$ne": [{ "$size": "$$c.Name" },0] },
            { "$ne": [{ "$size": "$$c.Tournaments" },0] }
          ]
        }
      } 
    }  
  }}
])
返回结果:

/* 1 */
{
    "_id" : ObjectId("597846358bbbc4440895f2e8"),
    "Name" : [ 
        {
            "k" : "en-US",
            "v" : "Soccer"
        }, 
        {
            "k" : "fr-FR",
            "v" : "Football"
        }
    ],
    "Categories" : [ 
        {
            "Name" : [ 
                {
                    "k" : "en-US",
                    "v" : "France"
                }, 
                {
                    "k" : "fr-FR",
                    "v" : "France"
                }
            ],
            "Tournaments" : [ 
                {
                    "Name" : [ 
                        {
                            "k" : "en-US",
                            "v" : "Ligue 1"
                        }, 
                        {
                            "k" : "fr-FR",
                            "v" : "Ligue 1"
                        }
                    ]
                }
            ]
        }
    ]
}
关键是每个数组都需要一个数组,而在外部级别,由于对包含的数组执行“内部”操作,您要寻找的不是
0

由于“内部”数组的内容会因此发生变化,“外部”数组需要一个数组来返回“已更改”的元素

因此,在结构方面,“Categories”需要一个元素,因为它有内部元素。“内部”
“锦标赛”
也因为同样的原因需要一个。一直到最终属性所需的每个数组,以及每个带条件的包装数组

这是通用逻辑模式,它通过对每个嵌套级别重复该模式来工作。尽管如此,这还是相当可怕的。这就是为什么你真的应该不惜一切代价避免像这样的“筑巢”。增加的复杂性几乎总是超过任何可感知的收益

我还应该注意到您有点过火了,您实际上只需要在
“Categories”
数组级别使用它,因为这是它的元素唯一需要满足多个条件的东西

子元素可以使用普通元素,因为它们只是各自数组中的“奇异”条件。因此,这确实在某种程度上减少了简洁的语法,并且仍然完全匹配相同的文档


非常感谢你。我使用嵌套数组是因为在我的设计中,如果没有父对象,这些嵌入文档将永远不会被查询。我们试图避免基于每种类型一个集合的关系设计。但是,您是对的,我只尝试更新根级别数组(成功),但是如果不替换整个对象,似乎不可能更新嵌套数组。非常感谢。我使用嵌套数组是因为在我的设计中,如果没有父对象,这些嵌入文档将永远不会被查询。我们试图避免基于每种类型一个集合的关系设计。但是,您是对的,我只尝试更新根级别的数组(成功),但似乎不可能在不替换整个对象的情况下更新嵌套数组。