Arrays 有条件地投影匹配数组项
我有一个名为Arrays 有条件地投影匹配数组项,arrays,mongodb,mongodb-query,aggregation-framework,Arrays,Mongodb,Mongodb Query,Aggregation Framework,我有一个名为questions的集合,其中包含以下文档: { "formats": [ { "language_id": 1, "text": "question text1" }, { "language_id": 2, "text": "question text 2" } ], "qid": "HQSRFA3
questions
的集合,其中包含以下文档:
{
"formats": [
{
"language_id": 1,
"text": "question text1"
},
{
"language_id": 2,
"text": "question text 2"
}
],
"qid": "HQSRFA3T"
}
db.questions.aggregate([ { $match: {'qid': 'HQSRFA3T'}}, { $project: {
formats: {
$filter: {
input: '$formats',
as: 'format',
cond: {
$or: [
{ $eq: ['$$format.language_id', 1] },
{ $eq: ['$$format.language_id', 3] }
]
}
}
},
_id: 0
}}])
我想编写一个查询,如果特定的language\u id
不存在,那么默认情况下应该返回带有1的language\u id
到目前为止,我尝试了两个查询:
db.questions.aggregate([
{
$match: {
'qid': 'HQSRFA3T'
}
},
{
$project: {
formats: {
$ifNull: [
{ $filter: { input: '$formats', as: 'format', cond: {$eq: ['$$format.language_id', 3]}} },
{ $filter: { input: '$formats', as: 'format', cond: {$eq: ['$$format.language_id', 1]}} }
]
},
_id: 0
}
}
])
此查询的结果如下所示:
{
"formats": [
{
"language_id": 1,
"text": "question text1"
},
{
"language_id": 2,
"text": "question text 2"
}
],
"qid": "HQSRFA3T"
}
db.questions.aggregate([ { $match: {'qid': 'HQSRFA3T'}}, { $project: {
formats: {
$filter: {
input: '$formats',
as: 'format',
cond: {
$or: [
{ $eq: ['$$format.language_id', 1] },
{ $eq: ['$$format.language_id', 3] }
]
}
}
},
_id: 0
}}])
{“格式”:[]}
然后还有另一个类似这样的查询:
{
"formats": [
{
"language_id": 1,
"text": "question text1"
},
{
"language_id": 2,
"text": "question text 2"
}
],
"qid": "HQSRFA3T"
}
db.questions.aggregate([ { $match: {'qid': 'HQSRFA3T'}}, { $project: {
formats: {
$filter: {
input: '$formats',
as: 'format',
cond: {
$or: [
{ $eq: ['$$format.language_id', 1] },
{ $eq: ['$$format.language_id', 3] }
]
}
}
},
_id: 0
}}])
如果数组中同时存在语言id
,此查询将返回两个元素。有几种方法:
理想情况下,您可以使用MongoDB 3.4,然后将其与以下内容结合使用:
如果您真正想要的是匹配的“text”
,则需要稍加修改:
db.questions.aggregate([
{ "$match": { "qid": "HQSRFA3T" } },
{ "$project": {
"text": {
"$cond": {
"if": { "$in": [ 3, "$formats.language_id"] },
"then": {
"$arrayElemAt": [
"$formats.text",
{ "$indexOfArray": [ "$formats.language_id", 3 ] }
]
},
"else": {
"$arrayElemAt": [
"$formats.text",
{ "$indexOfArray": [ "$formats.language_id", 1 ] }
]
}
}
}}
}
])
这是因为如果返回指示“未找到”的-1
,则会相应地进行分支:
或者,与以下内容一起使用:
如果您至少有MongoDB 3.2,您甚至可以在最后一个表单上更改,只返回位置0
处的“单个”匹配数组元素
db.questions.aggregate([
{ "$match": { "qid": "HQSRFA3T" } },
{ "$project": {
"formats": {
"$cond": {
"if": { "$gt": [
{ "$size": {
"$filter": {
"input": "$formats",
"cond": { "$eq": [ "$$this.language_id", 3 ] }
}
}},
0
]},
"then": {
"$arrayElemAt": [
{ "$filter": {
"input": "$formats",
"cond": { "$eq": [ "$$this.language_id", 3 ] }
}},
0
]
},
"else": {
"$arrayElemAt": [
{ "$filter": {
"input": "$formats",
"cond": { "$eq": [ "$$this.language_id", 1 ] }
}},
0
]
}
}
}
}}
])
如果使用了条件的上的其他选项,以匹配数组元素上的比较:
"if": { "$in": [ 3, "$formats.language_id" ] }
但由于这需要MongoDB 3.4,因此您也可以使用操作符
尝试“强制”多个匹配,然后最终放弃其中一个,这没有什么意义,但您可以通过以下方式“实现”:
所以它就在那里,但这只是额外的工作,几乎没有什么收益,因为在最好的情况下,条件与“默认”情况匹配,并且您仍然需要“过滤掉”仅为“首选”情况无论如何都要匹配。第一个查询将返回错误的结果,$indexOfArray
返回-1,$arrayElemAt
根据文档给出数组中的最后一个元素。@RahulSharma Argh!当然,您的权限$ifNull
可能不是最好的选择。我想编写一个查询,返回到使用第三个查询正确实现的语言id
1。我刚刚指出,如果$indexOfArray返回-1,$arrayElemAt不会返回null。无论如何,感谢您对第三个查询的帮助。@RahulSharma我还是修改了第一个查询$ifNull
不起作用,因为没有返回null
,因此$cond
在所有情况下都有效。