Ответ 1
$redact
оператор конвейера действительно не тот, который вы хотите для этого случая. То, что он хочет сделать, рекурсивно "спускается" через структуру документа и оценивает условия на каждом "уровне", чтобы увидеть, какие действия он предпримет.
В вашем случае на верхнем уровне документа нет поля "имя", чтобы соответствовать условию, поэтому в результате весь документ "обрезается".
Вы после фильтрации массивов, и в этом случае, когда вы не хотите использовать $unwind
и $match
, то вы можете использовать новые операторы, такие как $map
:
db.cars.aggregate([
{ "$match": { "class": "coupe" }},
{ "$project": {
"equipment": {
"$setDifference": [
{ "$map": {
"input": "$equipment",
"as": "el",
"in": {
"$cond": [
{ "$or": [
{ "$eq": [ "$$el.name", "airbag" ] },
{ "$eq": [ "$$el.name", "led" ] }
]},
{ "$cond": [ 1, "$$el", 0 ] },
false
]
}
}},
[false]
]
}
}}
])
Оператор $map
работает с массивом и оценивает логическое условие для всех элементов, в этот случай в $cond
. То же самое, что $in
, которое не является логическим оператором в этом смысле, использует $or
, который является логическим оператором для структуры агрегации.
Как любой элемент, который не удовлетворяет условию, вернет false
, теперь вам нужно "удалить" все значения false
. Это помогает $setDifference
, который будет делать это путем сравнения.
В результате вы хотите:
{
"_id" : ObjectId("53b2725120edfc7d0df2f0b1"),
"equipment" : [
{
"name" : "airbag",
"cost" : 120
},
{
"name" : "led",
"cost" : 170
}
]
}
{
"_id" : ObjectId("53b2725120edfc7d0df2f0b2"),
"equipment" : [
{
"name" : "airbag",
"cost" : 180
},
{
"name" : "led",
"cost" : 120
}
]
}
Если вы действительно намеревались использовать $redact
, то всегда есть этот надуманный пример:
db.cars.aggregate([
{ "$match": { "class": "coupe" }},
{ "$redact": {
"$cond": {
"if": {
"$or": [
{ "$eq": [
{ "$ifNull": ["$name", "airbag"] },
"airbag"
]},
{ "$eq": [
{ "$ifNull": ["$name", "led"] },
"led"
]},
]
},
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}}
])
Таким образом, в основном, убедитесь, что если поле не существует вообще при нисходящем, оно будет "искусственно" создавать тот, который будет соответствовать, так что уровень не будет "обрезанным". Если поле существует, используется найденное значение, и если это не соответствует условию, оно будет обрезано.