Robomongo: предел превышения памяти для $ group

Я использую скрипт для удаления дубликатов на монго, он работал в коллекции из 10 элементов, которые я использовал в качестве теста, но когда я использовал реальную коллекцию с 6 миллионами документов, я получаю сообщение об ошибке.

Это сценарий, который я запустил в Robomongo (теперь он известен как Robo 3T):

var bulk = db.getCollection('RAW_COLLECTION').initializeOrderedBulkOp();
var count = 0;

db.getCollection('RAW_COLLECTION').aggregate([
  // Group on unique value storing _id values to array and count 
  { "$group": {
    "_id": { RegisterNumber: "$RegisterNumber", Region: "$Region" },
    "ids": { "$push": "$_id" },
    "count": { "$sum": 1 }      
  }},
  // Only return things that matched more than once. i.e a duplicate
  { "$match": { "count": { "$gt": 1 } } }
]).forEach(function(doc) {
  var keep = doc.ids.shift();     // takes the first _id from the array

  bulk.find({ "_id": { "$in": doc.ids }}).remove(); // remove all remaining _id matches
  count++;

  if ( count % 500 == 0 ) {  // only actually write per 500 operations
      bulk.execute();
      bulk = db.getCollection('RAW_COLLECTION').initializeOrderedBulkOp();  // re-init after execute
  }
});

// Clear any queued operations
if ( count % 500 != 0 )
    bulk.execute();

Это сообщение об ошибке:

Error: command failed: {
    "errmsg" : "exception: Exceeded memory limit for $group, but didn't allow external sort. Pass allowDiskUse:true to opt in.",
    "code" : 16945,
    "ok" : 0
} : aggregate failed :
[email protected]/mongo/shell/utils.js:23:13
[email protected]/mongo/shell/assert.js:13:14
[email protected]/mongo/shell/assert.js:266:5
[email protected]/mongo/shell/collection.js:1215:5
@(shell):1:1

Итак, мне нужно настроить allowDiskUse:true на работу? Где я делаю это в скрипте, и есть ли проблемы с этим?

Ответы

Ответ 1

{ allowDiskUse: true } 

Должен быть размещен сразу после конвейера агрегации.

В вашем коде это должно выглядеть так:

db.getCollection('RAW_COLLECTION').aggregate([
  // Group on unique value storing _id values to array and count 
  { "$group": {
    "_id": { RegisterNumber: "$RegisterNumber", Region: "$Region" },
    "ids": { "$push": "$_id" },
    "count": { "$sum": 1 }      
  }},
  // Only return things that matched more than once. i.e a duplicate
  { "$match": { "count": { "$gt": 1 } } }
], { allowDiskUse: true } )

Ответ 2

Из документов MongoDB

Уровень $ group имеет предел в 100 мегабайт оперативной памяти. По умолчанию, если эта ступень превышает этот предел, $ group выдает ошибку. Однако, чтобы разрешить обработку больших наборов данных, установите для параметра allowDiskUse значение true, чтобы включить операции $ group для записи во временные файлы. Для получения дополнительной информации см. Метод db.collection.aggregate() и команду aggregate.

Ответ 3

Всегда лучше использовать сопоставление перед группой, когда у вас большие данные. Если вы используете матч перед группой, вы не попадете в эту проблему.

db.getCollection('sample').aggregate([
   {$match:{State:'TAMIL NADU'}},
   {$group:{
       _id:{DiseCode:"$code", State:"$State"},
       totalCount:{$sum:1}
   }},

   {
     $project:{
        Code:"$_id.code",
        totalCount:"$totalCount",
        _id:0 
     }   

   }

])

Если вы действительно преодолели эту проблему без совпадений, то решение будет { allowDiskUse: true }