2014-12-16 2 views
0

Это моя коллекция теста:Проверьте встраивать существует - агрегация рамка MongoDB

>db.test.find() 
{ 
    "_id": ObjectId("54906479e89cdf95f5fb2351"), 
    "reports": [ 
     { 
      "desc": "xxx", 
      "order": {"$id": ObjectId("53fbede62827b89e4f86c12e")} 
     } 
    ] 
}, 
{ 
    "_id": ObjectId("54906515e89cdf95f5fb2352"), 
    "reports": [ 
     { 
      "desc": "xxx" 
     } 
    ] 
}, 
{ 
    "_id": ObjectId("549067d3e89cdf95f5fb2353"), 
    "reports": [ 
     { 
      "desc": "xxx" 
     } 
    ] 
} 

Я хочу, чтобы сосчитать все документы и документы с порядком, так:

>db.test.aggregate({ 
    $group: { 
     _id: null, 
     all: { 
      $sum: 1 
     }, 
     order: { 
      $sum: { 
       "$cond": [ 
        { 
         "$ifNull": ["$reports.order", false] 
        }, 
        1, 
        0 
       ] 
      } 
     } 
    } 
}) 

и мои результаты:

{ 
    "result" : [ 
     { 
      "_id" : null, 
      "all" : 3, 
      "order" : 3 
     } 
    ], 
    "ok" : 1 
} 

но ожидаемый:

{ 
    "result" : [ 
     { 
      "_id" : null, 
      "all" : 3, 
      "order" : 1 
     } 
    ], 
    "ok" : 1 
} 

Не имеет значения, что я буду устанавливать - «$ reports.order», «$ reports.xxx» и т. Д., Проверка агрегации проверяется только в том случае, если отчеты о поле существует, игнорирует вставку. $ ifNull и $ eq не работают с вложенными документами? Есть ли способ сделать что-то вроде этого

db.test.find({"reports.order": {$exists: 1}}) 

в рамках агрегации? Извините за мой английский, и я надеюсь, что вы поняли, что я хочу вам показать :)

+0

Почему не просто 'db.test.count()' для подсчета общего количества документов и 'db.test.count ({" reports.order ": {" $ exists ": true}})' to подсчитать количество документов с заказом? – wdberkeley

+0

, потому что я хочу сделать это в одном запросе, это часть некоторого статистического построителя запросов, который был всего лишь примером кода, чтобы показать проблему – Bartosz

ответ

0

Я думаю, что это не работает, потому что поле «reports» содержит массив, а не объект.

Я имею в виду, ваша агрегация работает, как вы ожидаете в этой коллекции:

>db.test.find() 
{ 
    "_id": ObjectId("54906479e89cdf95f5fb2351"), 
    "reports": 
     { 
      "desc": "xxx", 
      "order": {"$id": ObjectId("53fbede62827b89e4f86c12e")} 
     } 
}, 
{ 
    "_id": ObjectId("54906515e89cdf95f5fb2352"), 
    "reports": 
     { 
      "desc": "xxx" 
     } 

}, 
{ 
    "_id": ObjectId("549067d3e89cdf95f5fb2353"), 
    "reports": 
     { 
      "desc": "xxx" 
     } 

} 

Следует заметить, что я удалил «[» и «]», так что теперь это объект, а не массив (один к-одному).

Поскольку у вас есть массив внутри поля «отчет», вам необходимо развернуть массив для вывода одного документа для каждого элемента. Я полагаю, что если у вас есть два поля «порядок» внутри массива «reports», вы хотите только его подсчитать. Я имею в виду:

"reports": [ 
     { 
      "desc": "xxx", 
      "order": {"$id": ObjectId("53fbede62827b89e4f86c12e")}, 
      "order": "yyy", 
     } 
    ] 

Должно рассчитываться только как единое целое для окончательной суммы «заказа» объекта.

В этом случае вам нужно расслабиться, группы по _id (потому что предыдущий пример выводит два документа для того же _id) и затем группа снова сосчитать все документы:

db.test.aggregate([ 
    {$unwind: '$reports'}, 
    {$group:{ 
     _id:"$_id", 
     order:{$sum:{"$cond": [ 
       { 
        "$ifNull": ["$reports.order", false] 
       }, 
       1, 
       0 
       ] 
      } 
     } 
    }}, 
    {$group:{ 
     _id:null, 
     all:{$sum:1}, 
     order: { 
      $sum:{ 
       "$cond": [{$eq: ['$order', 0]}, 0, 1] 
      } 
     } 
}}]) 

Может Существует более короткий решение, но это работает.

Смежные вопросы