#javascript #mongodb #aggregation-framework #updates
#javascript #mongodb #агрегация-фреймворк #Обновления
Вопрос:
По сути, я выполнил агрегацию, чтобы получить общее количество и список объектов, которые сформировали общее количество.
Теперь мне нужно обновить исходную таблицу с помощью агрегированного идентификатора объекта для элементов, которые вносят вклад в агрегацию. В основном формирование отношения в обоих направлениях.
coll.aggregate([
{ "$match": {"elig": 1, "nid" : null, "cncl" : null } },
{ "$group": {
"_id": "$nkey",
"cumqty": {"$sum": "$pr_qty.qty" },
"netted" : { "$push" : "$_id" }
}},
{ "$project": {
"nkey":"$nkey" ,
"cumqty": "$cumqty",
"netted" : "$netted" ,
"_id" : 0
}},
{ "$out": aggcollnm }
])
Теперь в объединенной таблице есть список идентификаторов объектов, сформированный с помощью $push .
Скажем, doc1, doc2 и doc3 сформировали agg1, а в списке agg1 есть doc1, doc2 и doc3. Я хочу, чтобы doc1, doc2 и doc3 имели идентификатор agg1 в качестве идентификатора сети.
Итак, я сделал следующее
coll.find().forEach( function(elem) {
coll.update (
{ "_id" : elem._id },
{ "$set" : { nid : aggcoll.aggregate ( [
{ "$unwind" : "$netted" } ,
{ "$match" : { "netted" : elem._id } },
{ "$project" : { "_id" :1 } }
] )._firstBatch[0]
}}
)
})
Он отлично работал в меньшем наборе. Но для документов 1M сбой с приведенной ниже ошибкой.
2014-06-30T09:48:40.577 0100 Ошибка: getMore: курсор не существует на сервере, возможен перезапуск или тайм-аут? в src/mongo/shell/query.js:116 не удалось загрузить: ./netting.js
Есть ли лучший способ сделать это.
Ответ №1:
Вы используете MongoDB 2.6, поэтому есть способы более эффективного обновления, так как ваша общая обработка, похоже, обратная. Вы должны зацикливать свой «aggcoll», а затем обновлять свою цель изнутри этого:
var batch = coll.initializeOrderedBulkOp();
counter = 0;
aggcoll.find().forEach(function(agg) {
batch.find({ "_id": { "$in": agg.netted }}).update({ "$set: { "nid": agg._id } });
counter ;
if ( counter % 1000 == 0 ) {
batch.execute();
counter = 0;
batch = coll.initializeOrderedBulkOp();
}
});
if ( counter > 0 )
batch.execute();
Ваш «встроенный» агрегатный оператор был не очень эффективным способом сделать то, что вы пытались, и сильно замедлил бы работу. Здесь не только выполняется выдача обновлений для всех сопоставленных _id
значений с помощью $in
as, поскольку это операция «множественного» обновления, но и общее использование API массовых операций сокращает трафик на сервер и затрачиваемое время.
На самом деле, я вообще не знаю, зачем вы это делаете, поскольку у вас уже должна быть «связанная» информация. Взгляните на свой исходный агрегат:
{ "$group": {
"_id": "$nkey",
По какой-то причине вы изменили это так, чтобы оно больше не _id
было ключом этой новой коллекции, когда вы ее записывали. Очевидно, что это поле присутствует во всех документах, из которых вы были получены, и его просто следовало оставить в качестве нового первичного ключа.