Есть несколько способов:
В идеале у вас есть $indexOfArray
из MongoDB 3.4, тогда вы можете использовать это в сочетании с $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 ] }
}
}
}
}
}}
])
Вы даже можете изменить в последней форме с помощью $arrayElemAt
, чтобы просто вернуть «единственный» соответствующий элемент массива в позиции 0
, если вы хотя быиметь MongoDB 3.2.
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
соответствует случаю «по умолчанию», и вам все еще необходимо «отфильтровать» только «предпочтительный»"в любом случае совпадать.