0

Я много искал, прежде чем задавать этот вопрос, но не смог найти никакой соответствующей информации.Как агрегировать данные в не ассоциативном массиве в MongoDb

Так вот:

Моя проблема заключается в том, что у меня есть коллекция Монго в следующем формате:

{ 
    "_id" : ObjectId("55bf4031eb8ac118a4b3110e"), 
    "sid" : 1, 
    "plugin_count" : [ 
     0, 
     0, 
     0, 
     1, 
     0, 
     1, 
     0, 
     0, 
     0, 
     0 
    ], 

}, 
{ 
    "_id" : ObjectId("55bf4031eb8ac118a4b3110e"), 
    "sid" : 1, 
    "plugin_count" : [ 
     2, 
     1, 
     0, 
     6, 
     0, 
     10, 
     12, 
     0, 
     16, 
     22 
    ], 

} 

Теперь то, что я хочу сделать это, я хочу, чтобы добавить все элементы, присутствующие в не ассоциативный массив индивидуально и выводить их, как это:

{ 
    "result": [ 
     { 
      "_id": 1, 
      "plugin_count": [ 
       2, 
       1, 
       0, 
       7, 
       0, 
       11, 
       12, 
       0, 
       16, 
       22 
      ] 
     } 
    ], 
    "ok": 1 
} 

Мой запрос выглядит следующим образом

db.plugin_table.aggregate([ 
    { 
     "$match" : { 
      "sid" : { 
       "$in" : [1] 
      } 
     } 
    }, 
    { 
     "$unwind" : "$plugin_count" 
    }, 
    { 
     "$group" : { 
      "_id": 1, 
      "plugin_count" : { 
       "$sum" : "$plugin_count" 
      } 
     } 
    } 
]); 

Но я получаю следующий вывод:

{ 
    "result": [ 
     { 
      "_id": 1, 
      "plugin_count": 0 
     } 
    ], 
    "ok": 1 
} 

Пожалуйста, помогите я буквально вытягивать свои волоски. :(

ответ

0

Там действительно нет разумного способа сделать это с рамками агрегации. Проблема здесь является отслеживание «индекса» положение элементов массива, из которых не существует ничего, что может это сделать.

лучше всего здесь 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.

+0

Благодарим вас за предложение @Blakes. Фактически мы не использовали индексы для экономии места, так как эта коллекция состоит из 1 миллиона + записей. Но обязательно используйте часть mapReduce. Один быстрый вопрос, хотя, будет использовать mapReduce, какое-либо влияние на производительность? –

+0

@LankeshZade Я говорю о «индексах массива», что означает «позиция в массиве», а не «индексы базы данных», как вы ошибаетесь. Что касается производительности, mapReduce использует JavaScript для его выполнения команды. Таким образом, да, есть затраты на множество операций с агрегацией из-за этой оценки и «раздувания» типов BSON с типами JavaScipt. Однако, как я уже сказал в ответе, в то время как агрегат использует собственные операторы, «стоимость» обработки '$ unwind' здесь, вероятно, больше, чем производительность, полученная от mapReduce. Оцените две формы, где это возможно. –

+0

Будете держать это в виду. Спасибо за ваше время @Blakes. Извините за задержку с ответом. –