我使用以下代表运动的集合>类别>比赛。
{
"_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 })
但是,我不能只在类别对象中收到匹配的锦标赛。 使用这个问题中的答案:MongoDB Projection of Nested Arrays,我已经构建了一个聚合:
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
}
}
}
}
}
])
我尝试使用一个条件,但当我使用$ anyElementTrue然后$时,MongoDB无法识别(使用未定义的变量:)$$ KEEP和$$ PRUNE($redact)映射在“名称”属性上。
我的问题:如何检查名称集合是否包含我的字符串?
答案 0 :(得分:0)
我更感到惊讶的是,在您提到的答案中,我并非没有"强烈建议您不要嵌套数组"像这样。在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"
}
]
}
]
}
]
}
重点是每个数组都需要一个$filter
,而在外层,您正在寻找$size
而不是0
因为"内部&#34 ;对包含的数组进行$filter
次操作。
因为"内部"因此,数组可以改变内容,"外部"数组需要$map
才能返回"更改"元件。
因此,就结构而言,"Categories"
需要$map
,因为它具有内部元素。并且"内部"出于同样的原因,"Tournaments"
需要$map
。每个数组一直到最终属性都需要$filter
,每个包含$map
的数据包都有一个$filter
$size
条件。
这是一般逻辑模式,它通过为每个嵌套级别重复该模式来工作。如上所述,它非常可怕。这就是为什么你真的应该避免"嵌套"这样不惜一切代价。增加的复杂性总是超过任何感知的收益。
我还应该注意到你对
$elemMatch
有点过分了,你真的只需要在"Categories"
数组级别,因为那是唯一有多个条件需要满足的它的元素。子元素可以使用普通"Dot Notation",因为它们只是"单数"各自阵列中的条件。所以这确实减少了简洁的语法,并且仍然匹配完全相同的文档。