web-dev-qa-db-fra.com

Robomongo: limite de mémoire dépassée pour $ groupe

J’utilise un script pour supprimer les doublons sur mongo, cela a fonctionné dans une collection de 10 éléments que j’ai utilisés à titre de test, mais lorsqu’il est utilisé pour la collection réelle avec 6 millions de documents, j’obtiens une erreur.

Voici le script que j'ai exécuté dans Robomongo (maintenant connu sous le nom de 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();

C'est le message d'erreur:

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 :
_getErrorWithCode@src/mongo/Shell/utils.js:23:13
doassert@src/mongo/Shell/assert.js:13:14
assert.commandWorked@src/mongo/Shell/assert.js:266:5
DBCollection.prototype.aggregate@src/mongo/Shell/collection.js:1215:5
@(Shell):1:1

J'ai donc besoin de configurer allowDiskUse:true pour qu'il fonctionne? Où est-ce que je fais cela dans le script et y a-t-il un problème à le faire?

11
kadzu
{ allowDiskUse: true } 

Devrait être placé juste après le pipeline d'agrégation.

Dans votre code cela devrait aller comme ceci: 

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 } )
27
Astro

De la documentation MongoDB

La phase de groupe $ a une limite de 100 mégaoctets de RAM. Par défaut, si la phase dépasse cette limite, $ group produira une erreur. Toutefois, pour permettre le traitement de grands ensembles de données, définissez allowDiskUse option à true pour permettre aux opérations du groupe $ d'écrire dans le fichier temporaire des dossiers. Voir la méthode db.collection.aggregate () et la commande d'agrégat pour plus de détails.

0
Sercan Ozdemir