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”
数组级别使用它,因为这是它的元素唯一需要满足多个条件的东西
子元素可以使用普通元素,因为它们只是各自数组中的“奇异”条件。因此,这确实在某种程度上减少了简洁的语法,并且仍然完全匹配相同的文档
非常感谢你。我使用嵌套数组是因为在我的设计中,如果没有父对象,这些嵌入文档将永远不会被查询。我们试图避免基于每种类型一个集合的关系设计。但是,您是对的,我只尝试更新根级别数组(成功),但是如果不替换整个对象,似乎不可能更新嵌套数组。非常感谢。我使用嵌套数组是因为在我的设计中,如果没有父对象,这些嵌入文档将永远不会被查询。我们试图避免基于每种类型一个集合的关系设计。但是,您是对的,我只尝试更新根级别的数组(成功),但似乎不可能在不替换整个对象的情况下更新嵌套数组。