Там действительно нет разумного способа сделать это с рамками агрегации. Проблема здесь является отслеживание «индекса» положение элементов массива, из которых не существует ничего, что может это сделать.
лучше всего здесь mapReduce, это может решить проблему довольно просто, а также весы для любого количества сгруппированных ключей:
db.plugin_table.mapReduce(
function() {
emit(this.sid, { plugin_count: this.plugin_count });
},
function (key,values) {
var result = { plugin_count: [] };
values.forEach(function(value) {
value.plugin_count.forEach(function(plugin,idx) {
if (result.plugin_count[idx] === undefined) {
result.plugin_count[idx] = plugin;
} else {
result.plugin_count[idx] += plugin;
}
});
});
return result;
},
{
"query": { "sid": 1 },
"out": { "inline": 1 }
}
)
Это производит требуемую мощность, albiet в том виде, MapReduce всегда производит выход с клавиши верхнего уровня от _id
a й value
:
{
"_id" : 1,
"value" : {
"plugin_count" : [
2,
1,
0,
7,
0,
11,
12,
0,
16,
22
]
}
}
Обратите внимание на алгоритм уменьшения здесь также обрабатывает массивы различной длины с легкостью, как все спарены позиции индекса или иным образом создается, если эта позиция не была уже присутствует в объединенном результате на ключ.
Единственный реальный способ рамки агрегации может справиться с этим уже есть данные на самом деле в «ассоциативный массив» вместо этого, или, по крайней мере, каждый элемент в качестве ассоциативного массива в себе, как это:
{
"_id" : ObjectId("55d32ffde12af47feb19bce7"),
"sid" : 1,
"plugin_count" : [
{
"pos" : 0,
"value" : 0
},
{
"pos" : 1,
"value" : 0
},
{
"pos" : 2,
"value" : 0
},
{
"pos" : 3,
"value" : 1
},
{
"pos" : 4,
"value" : 0
},
{
"pos" : 5,
"value" : 1
},
{
"pos" : 6,
"value" : 0
},
{
"pos" : 7,
"value" : 0
},
{
"pos" : 8,
"value" : 0
},
{
"pos" : 9,
"value" : 0
}
]
}
Это основное преобразование вдоль этих линий:
db.junk.find().forEach(function(doc) {
doc.plugin_count = doc.plugin_count.map(function(value,idx) {
return { "pos": idx, "value": value };
});
db.newjunk.insert(doc);
});
Тогда у вас есть базовая агрегация, по Simp группируя «сначала» по элементам «pos» и суммируя результаты. Окончательный массив может быть затем формируется путем группировки обратно в «ИДС»:
db.newjunk.aggregate([
{ "$match": { "sid": 1 } },
{ "$unwind": "$plugin_count" },
{ "$group": {
"_id": {
"sid": "$sid",
"pos": "$plugin_count.pos"
},
"value": { "$sum": "$plugin_count.value" }
}},
{ "$sort": { "_id": 1 } },
{ "$group": {
"_id": "$_id.sid",
"plugin_count": { "$push": "$value" }
}}
])
, который дает вам тот же результат, как раньше:
{ "_id" : 1, "plugin_count" : [ 2, 1, 0, 7, 0, 11, 12, 0, 16, 22 ] }
также отметить здесь, что вы могли бы избежать $sort
стадии здесь сохраняя ассоциативную информацию. Использование $group
не гарантирует, что позиции остаются неизменными, но с ассоциативной информацией это не требуется.
Итак, все сводится к тому, с чем вы можете жить. Если вы хотите сохранить простой массив в данных, вам понадобится mapReduce, чтобы получить результат. Если, однако, вы хотите изменить формат данных, то совокупный метод вполне возможен.
Однако это может быть хорошим случаем, когда в «крупном масштабе» процесс mapReduce будет бить процесс агрегации, избегая накладных расходов на обработку $unwind
.
Благодарим вас за предложение @Blakes. Фактически мы не использовали индексы для экономии места, так как эта коллекция состоит из 1 миллиона + записей. Но обязательно используйте часть mapReduce. Один быстрый вопрос, хотя, будет использовать mapReduce, какое-либо влияние на производительность? –
@LankeshZade Я говорю о «индексах массива», что означает «позиция в массиве», а не «индексы базы данных», как вы ошибаетесь. Что касается производительности, mapReduce использует JavaScript для его выполнения команды. Таким образом, да, есть затраты на множество операций с агрегацией из-за этой оценки и «раздувания» типов BSON с типами JavaScipt. Однако, как я уже сказал в ответе, в то время как агрегат использует собственные операторы, «стоимость» обработки '$ unwind' здесь, вероятно, больше, чем производительность, полученная от mapReduce. Оцените две формы, где это возможно. –
Будете держать это в виду. Спасибо за ваше время @Blakes. Извините за задержку с ответом. –