2015-10-29 1 views
1

Я делаю aggregation с project с cond. Что-то вроде этого ...

Пусть документ о:

{outter:{ 
    inner1:"blah", 
    innerOther:"somethingelse" 
}} 

Aggregation:

db.collection.aggregate([{ 
    $project : { 
     "outter.inner1":1, 
     "outter.inner2":{ 
      $cond : if:{"outter.innerOther":{$exists:true}}, 
        then:{"blah":"blah"}, 
        else:{"blah":"blah"} 
     } 
    } 
}]) 

Когда я запускаю это я получаю сообщение об ошибке: exception: dotted field names are only allowed at the top level на if техническом состоянии (я пробовал замены если с if:true и агрегация работает).

Это ошибка? Есть ли обходной путь без выполнения всего другого проекта, чтобы просто получить доступное поле без точки?

EDIT

Так что я нашел обходной путь, но все-таки хотелось бы, чтобы увидеть, если это ожидаемое поведение. Обходным путем является использование переменной в проекции через $let. Кроме того, похоже, что $exists недействителен expression, поэтому также необходимо внести следующие изменения.

db.collection.aggregate([{ 
    $project : { 
     "outter.inner1":1, 
     "outter.inner2":{ 
      $let :{ 
       vars:{innerOther:{$ifNull:["$outter.innerOther", "absent"]}}, 
      } 
      $cond : if:{$eq:["$$innerOther","absent"]}, 
        then:{"blah":"blah"}, 
        else:{"blah":"blah"} 
     } 
    } 
}]) 
+0

Является ли "Outter" массив? пожалуйста, можете ли вы показать свои документы? – styvane

+0

Outter - это субдокумент. –

ответ

1

Во-первых, вы не можете использовать $exists, потому что это справедливо только в выражении с оператором $match или в методе .find(). При этом вы можете использовать "dot notation" в состоянии if, но вам нужно указать prefix it with the $ sign, которого нет в вашем первом запросе. Кроме того, вы не можете возвращать литеральные пары ключ/значение объекта как значение или выражение, потому что оно не является допустимым aggregation expressions, вам нужно вместо этого использовать "dot notation".

Теперь один из способов сделать это, как вы упомянули, использует операцию $let и $project ион. Конечно, условный оператор $ifNull возвращает текущее значение поля, если оно существует, или замещающее выражение.

db.collection.aggregate([ 
    { $project: { 
     "outter.inner1": 1, 
     "outter.inner2.blah": { 
      $let: { 
       vars: { 
        "outterinner2": { 
         $ifNull: [ "$outter.innerOther", "absent" ] 
        } 
       }, 
       in: { 
        $cond: [ 
         { $eq: [ "$$outterinner2", "absent" ] }, 
         "blah", 
         "blah" 
        ] 
       } 
      } 
     } 
    }} 
]) 

Другой способ сделать это с помощью двух $project ионной стадии.

db.collection.aggregate([ 
    { $project: { 
     "inner1": "$outter.inner1", 
     "inner2": { 
      $ifNull: [ "$outter.innerOther", "absent" ] 
     } 
    }}, 
    { $project: { 
     "outter.inner1": "$inner1", 
     "outter.inner2.blah": { 
      $cond: [ 
       { $eq: ["$inner2", "absent"] }, 
       "blah", 
       "blah" 
      ] 
     } 
    }} 
]) 

Оба запроса дают что-то вроде этого:

{ 
     "_id" : ObjectId("5632713c8b13e9fb9cc474f2"), 
     "outter" : { 
       "inner1" : "blah", 
       "inner2" : { 
         "blah" : "blah" 
       } 
     } 
} 

EDIT:

"точечной нотации" допускается в операторе $cond. Например, следующий запрос использует «точечную нотацию».

db.collection.aggregate([ 
    { $project: { 
     "outter.inner1": 1, 
     "outter.inner2.blah": { 
      $cond: [ 
       { $eq: [ "$outter.innerOther", "somethingelse" ] }, 
       "anotherThing", 
       "nothing" 
      ] 
     } 
    }} 
]) 

и выходы:

{ 
    "_id" : ObjectId("56379b020d97b83cd1506650"), 
    "outter" : { 
      "inner1" : "blah", 
      "inner2" : { 
        "blah" : "anotherThing" 
      } 

    } 
} 
0

хммм .... и этим:

Model.aggregate([ 
        { 
         $project: { 
          name: 1, 
          "indexes.name":{ 
           $cond: { 
            if: {$eq:["$indexes.name",'стафилококки']}, 
            then: "$indexes.name", 
            else: null 
           } 
          }, 
          "indexes.units":1 
         } 
        } 
       ], callback) 

всегда возвращают "нуль" для имени.Индексы

[ 
    { _id: 564c6a5991b08dd017c2bd23, 
    name: ' воздух ', 
    indexes: [ [Object] ] }, 
    { _id: 564c6cf091b08dd017c2bd24, 
    name: 'repa ', 
    indexes: [ [Object] ] }, 
] 

где индексы:

[ { units: 'fvf', name: null } ] 
[ { units: 'КОЕ', name: null } ] 
+0

Я изучил мое дело выше. Его невероятное **, но «$ indexes.name» в $ cond преобразуется в массив ["стафилококки"]!? Хотя на самом деле это строка типа «единиц»! ** Итак, нет равенства (["стафилококки"]! = "Стафилококки"), а $ cond всегда возвращает false, например. ноль – meugen