有“几种”方法:
理想情况下,您拥有来自 MongoDB 3.4 的 $indexOfArray,然后您可以将其与 $in 结合使用:
db.questions.aggregate([
{ "$match": { "qid": "HQSRFA3T" } },
{ "$project": {
"formats": {
"$cond": {
"if": { "$in": [ 3, "$formats.language_id"] },
"then": {
"$arrayElemAt": [
"$formats",
{ "$indexOfArray": [ "$formats.language_id", 3 ] }
]
},
"else": {
"$arrayElemAt": [
"$formats",
{ "$indexOfArray": [ "$formats.language_id", 1 ] }
]
}
}
}}
}
])
如果你真正想要的是匹配的"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 ] }
]
}
}
}}
}
])
这是可行的,因为如果 $indexOfArray 返回 -1 表示“未找到”,那么 $cond 将相应地分支:
或者,使用$filter 和$size:
db.questions.aggregate([
{ "$match": { "qid": "HQSRFA3T" } },
{ "$project": {
"formats": {
"$cond": {
"if": { "$gt": [
{ "$size": {
"$filter": {
"input": "$formats",
"cond": { "$eq": [ "$$this.language_id", 3 ] }
}
}},
0
]},
"then": {
"$filter": {
"input": "$formats",
"cond": { "$eq": [ "$$this.language_id", 3 ] }
}
},
"else": {
"$filter": {
"input": "$formats",
"cond": { "$eq": [ "$$this.language_id", 1 ] }
}
}
}
}
}}
])
如果您至少有 MongoDB 3.2,您甚至可以使用 $arrayElemAt 更改最后一个表单,只返回位置 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
]
}
}
}
}}
])
$cond 上if 条件的其他替代方法是使用$in,以匹配数组元素的比较:
"if": { "$in": [ 3, "$formats.language_id" ] }
但既然这需要 MongoDB 3.4,那么您不妨改用 $indexOfArray 运算符。
尝试将多个匹配“强制”到$filter 然后最终放弃其中一个几乎没有什么意义,但是您“可以”使用$let 做到这一点:
db.questions.aggregate([
{ "$match": { "qid": "HQSRFA3T" } },
{ "$project": {
"formats": {
"$let": {
"vars": {
"formats": {
"$filter": {
"input": "$formats",
"cond": {
"$or": [
{ "$eq": [ "$$this.language_id", 1 ] },
{ "$eq": [ "$$this.language_id", 3 ] }
]
}
}
}
},
"in": {
"$cond": {
"if": {
"$gt": [
{ "$size": {
"$filter": {
"input": "$$formats",
"cond": { "$eq": [ "$$this.language_id", 3 ] }
}
}},
0
]
},
"then": {
"$filter": {
"input": "$$formats",
"cond": { "$eq": [ "$$this.language_id", 3 ] }
}
},
"else": {
"$filter": {
"input": "$$formats",
"cond": { "$eq": [ "$$this.language_id", 1 ] }
}
}
}
}
}
}
}}
])
所以它就在那里,但这只是额外的工作,几乎没有什么收获,因为$or 条件最多匹配“默认”情况,但无论如何您仍然需要“过滤掉”只有“首选”匹配。