2015-07-29 3 views
1

... и уменьшить вложенные документы по критерию фильтра?Как отсортировать по сумме поля поддокумента

I've получили следующие структуры данных

{ 
    "_id" : "PwS8gcfhaWLaudjaJ", 
    "name" : "Name of Document 1", 
    "subdocuments" : [ 
     { 
      "subdocumentsId" : "dqR9gPi7tNvzpEhEW", 
      "number" : 1 
     }, 
     { 
      "subdocumentsId" : "vTaPoQYdaDbqMH7Pg", 
      "number" : 1 
     }, 
     { 
      "subdocumentsId" : "tPJ45KqAzvFPBRstZ", 
      "number" : 3 
     } 
    ] 
} 
{ 
    "_id" : "PwS8gcfhaWLaudjaJ", 
    "name" : "Name of Document 2", 
    "subdocuments" : [ 
     { 
      "subdocumentsId" : "dqR9gPi7tNvzpEhEW", 
      "number" : 2 
     }, 
     { 
      "subdocumentsId" : "tPJ45KqAzvFPBRstZ", 
      "number" : 5 
     } 
    ] 
} 

Как построить запрос, чтобы получить результат ниже

{ 
    "_id" : "PwS8gcfhaWLaudjaJ", 
    "name" : "Name of Document 2", 
    "subdocuments" : [ 
     { 
      "subdocumentsId" : "dqR9gPi7tNvzpEhEW", 
      "number" : 2 
     }, 
     { 
      "subdocumentsId" : "tPJ45KqAzvFPBRstZ", 
      "number" : 5 
     } 
    ] 
} 
{ 
    "_id" : "PwS8gcfhaWLaudjaJ", 
    "name" : "Name of Document 1", 
    "subdocuments" : [ 
     { 
      "subdocumentsId" : "dqR9gPi7tNvzpEhEW", 
      "number" : 1 
     }, 
     { 
      "subdocumentsId" : "tPJ45KqAzvFPBRstZ", 
      "number" : 3 
     } 
    ] 
} 

... и вот мой текущий запрос

var filterIds = ['dqR9gPi7tNvzpEhEW','tPJ45KqAzvFPBRstZ']; 

db.Documents 
.aggregate([ 
{ 
    $match: { 
     'subdocuments.subdocumentsId': { 
      $in: filterIds 
     } 
    } 
}, { 
    $project: { 
     _id: 1, 
     name: 1, 
     totalNumber: { 
      $sum: '$subdocuments.number' 
     } 
    } 
}, { 
    $sort: { 
     totalNumber: 1 
    } 
} 
]) 

Я не могу работать с $ sum-выражением в $ project-operation. Он доступен только для $ group.

Есть ли общее обходное решение, или можно получить результат с помощью $ group?

Возможно, кому-то может помочь, пожалуйста?

ответ

1

Вы должны использовать $unwind при работе с массивами. Также у вас есть две $group операции здесь с $sort между:

db.Documents.aggregate([ 
    // Select documents 
    { "$match": { 
     "subdocuments.subdocumentsId": { 
      "$in": filterIds 
     } 
    }}, 

    // Denormalize array 
    { "$unwind": "subdocuments" } 

    // Filter array elements 
    { "$match": { 
     "subdocuments.subdocumentsId": { 
      "$in": filterIds 
     } 
    }}, 

    // Get array sum  
    { "$group": { 
     "_id": { 
      "_id": "$_id", 
      "name": "$name", 
      "subId": "$subdocuments.subdocumentsId" 
     }, 
     "number": { "$sum": "$subdocuments.number" } 
    }}, 

    // Sort the results 
    { "$sort": { "_id._id": 1, "number": 1 } }, 

    // Group back to documents 
    { "$group": { 
     "_id": "$_id._id", 
     "name": { "$first": "$_id.name" }, 
     "subdocuments": { "$push": { 
      "subdocumentsId": "$_id.subId", 
      "number": "$number" 
     }}, 
     "total": { "$sum": "$number" } 
    }}, 

    // Sort at the end, decending for largest first 
    { "$sort": { "total": -1 } } 
]) 

То есть, если вы «суммируя» ваши отфильтрованные результаты от их uinique «subdocumentId» значения, где эти значения не являются уникальными. Если вы только фильтрации затем уменьшить шаги:

db.Documents.aggregate([ 
    // Select documents 
    { "$match": { 
     "subdocuments.subdocumentsId": { 
      "$in": filterIds 
     } 
    }}, 

    // Denormalize array 
    { "$unwind": "subdocuments" } 

    // Filter array elements 
    { "$match": { 
     "subdocuments.subdocumentsId": { 
      "$in": filterIds 
     } 
    }}, 

    // Group back to documents 
    { "$group": { 
     "_id": "$_id", 
     "name": { "$first": "$name" }, 
     "subdocuments": { 
      "$push": "$subdocuments" 
     }, 
     "total": { "$sum": "$subdocuments.number" } 
    }}, 

    // Sort at the end, decending for largest first 
    { "$sort": { "total": -1 } } 
]) 
+0

Так здорово, спасибо вам большое! Это то, что я искал. – moradec

1

Пожалуйста, попробуйте ниже запрос:

Ниже приведены шаги, а затем, чтобы получить результат:

1) раскрутиться ваши вложенные документы

2) хранить только те документы, которые соответствуют фильтру "filterIds " критерии

3) группировать документы на основе e_id, а также сохранить сумму поля «subdocuments.number», чтобы мы могли сортировать на основе этого.

4) сортировать по полю «subdocuments.number» (tot) в порядке убывания.

5) наконец-то проект или diplay в формате, который вам нужен.

db.Documents.aggregate([ 
{ 
$unwind:"$subdocuments" 
}, 
{ 
$match:{"subdocuments.subdocumentsId" : {"$in" : filterIds }} 
}, 
{ 
$group:{ _id : { id : "$_id", name :"$name" }, 
      tot : { "$sum": "$subdocuments.number"} , 
      subdocuments : {"$push" : 
         {subdocumentsId:"$subdocuments.subdocumentsId", 
      number : "$subdocuments.number" } } } }, 
{ 
$sort:{tot : -1} 
}, 
{ 
$project:{_id:"$_id.id", name: "$_id.name", subdocuments:1} 
} 
]).pretty(); 

Таким образом, приведенный выше запрос извлекает вам желаемый результат (выход):

{ 
     "_id" : "PwS8gcfhaWLaudjaI", 
     "subdocuments" : [ 
       { 
         "subdocumentsId" : "dqR9gPi7tNvzpEhEW", 
         "number" : 2 
       }, 
       { 
         "subdocumentsId" : "tPJ45KqAzvFPBRstZ", 
         "number" : 5 
       } 
     ], 
     "name" : "Name of Document 2" 
} 
{ 
     "_id" : "PwS8gcfhaWLaudjaJ", 
     "subdocuments" : [ 
       { 
         "subdocumentsId" : "dqR9gPi7tNvzpEhEW", 
         "number" : 1 
       }, 
       { 
         "subdocumentsId" : "tPJ45KqAzvFPBRstZ", 
         "number" : 3 
       } 
     ], 
     "name" : "Name of Document 1" 
} 
+0

Большое спасибо вам, агрегационная часть просто потрясающая! – moradec

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