2015-12-25 5 views
9

Sto cercando di aggregare i dati dalla mia raccolta Mongo per produrre alcune statistiche per FreeCodeCamp creando un file json di grandi dimensioni dei dati da usare in seguito.Mongo aggregation e MongoError: eccezione: BufBuilder ha tentato di crescere() in 134217728 byte, oltre il limite di 64 MB

Sto correndo nell'errore nel titolo. Non sembrano esserci molte informazioni su questo, e gli altri post qui su SO non hanno una risposta. Sto usando l'ultima versione di MongoDB e dei driver.

Sospetto che esista un modo migliore per eseguire questa aggregazione, ma funziona correttamente su un sottoinsieme della mia raccolta. La mia collezione completa è ~ 7 GB.

che sto eseguendo lo script tramite node aggScript.js > ~/Desktop/output.json Ecco il codice in questione:

MongoClient.connect(secrets.db, function(err, database) { 
    if (err) { 
    throw err; 
    } 

    database.collection('user').aggregate([ 
    { 
     $match: { 
     'completedChallenges': { 
      $exists: true 
     } 
     } 
    }, 
    { 
     $match: { 
     'completedChallenges': { 
      $ne: '' 
     } 
     } 
    }, 
    { 
     $match: { 
     'completedChallenges': { 
      $ne: null 
     } 
     } 
    }, 
    { 
     $group: { 
     '_id': 1, 'completedChallenges': { 
      $addToSet: '$completedChallenges' 
     } 
     } 
    } 
    ], { 
    allowDiskUse: true 
    }, function(err, results) { 
    if (err) { throw err; } 
    var aggData = results.map(function(camper) { 
     return _.flatten(camper.completedChallenges.map(function(challenges) { 
     return challenges.map(function(challenge) { 
      return { 
      name: challenge.name, 
      completedDate: challenge.completedDate, 
      solution: challenge.solution 
      }; 
     }); 
     }), true); 
    }); 
    console.log(JSON.stringify(aggData)); 
    process.exit(0); 
    }); 
}); 

risposta

1

Aggregate restituisce un unico documento contenente tutti i dati dei risultati, che limita la quantità di dati che possono essere restituiti alla dimensione massima del documento BSON.

Supponendo che non vuole realmente tutti questi dati, ci sono due opzioni:

  • Uso aggregateCursor invece di aggregate. Ciò restituisce un cursore piuttosto che un singolo documento, che è possibile quindi iterare su
  • aggiungere uno stage $out come ultima fase della pipeline. Questo dice a mongodb di scrivere i dati di aggregazione nella raccolta specificata. Il comando di aggregazione non restituisce alcun dato e quindi si esegue una query su tale raccolta come si farebbe con qualsiasi altro.
+0

la funzione aggregateCursor è stata rimossa Il vecchio.il metodo di aggregazione() ora ha diviso personalità: vecchie varargs di ops gasdotti una serie di ops gasdotti come primo argomento, secondo "Opzioni" argomento '' '(come ad esempio {allowDiskUsage: true} )' '' – Benoit

1

significa solo che l'oggetto risultato si sta costruendo è diventato troppo grande. Questo tipo di problema non dovrebbe essere influenzato dalla versione. The fix implemented for 2.5.0 only prevents the crash from occurring.

È necessario filtrare ($ corrisponde) correttamente per ottenere i dati necessari. Raggruppa anche i campi appropriati. I risultati vengono inseriti in un buffer di 64 MB. Quindi riduci i tuoi dati. $project solo le colonne necessarie nel risultato. Non interi documenti.

È possibile combinare gli oggetti di corrispondenza 3 $ in singoli per ridurre le condotte.

{ 
    $match: { 
    'completedChallenges': { 
     $exists: true, 
     $ne: null, 
     $ne: "" 
    } 
    } 
} 
+1

"La correzione implementata per 2.5.0 impedisce solo l'arresto anomalo." Parti della tua risposta sembrano copia/incolla da qui: https://jira.mongodb.org/browse/SERVER-9538, dovresti fare riferimento se stai parafrasando – JoeRocc

+0

@JoeRocc: Hai dimenticato di aggiungere il link. Aggiunto ora. Puoi anche modificare la risposta e aggiungere il link. Grazie per la notifica. –

0

ho avuto questo problema e non ho potuto eseguire il debug del problema così ho finito per abbandonare l'approccio di aggregazione. Invece ho solo ripetuto ogni voce e ho creato una nuova collezione. Ecco uno script di shell ridotta che potrebbe aiutare a vedere quello che voglio dire:

db.new_collection.ensureIndex({my_key:1}); //for performance, not a necessity 
db.old_collection.find({}).noCursorTimeout().forEach(function(doc) { 

    db.new_collection.update(
     { my_key: doc.my_key }, 
     { 
      $push: { stuff: doc.stuff, other_stuff: doc.other_stuff}, 
      $inc: { thing: doc.thing}, 
     }, 
     { upsert: true } 
    ); 

}); 

Non credo che questo approccio avrebbe tutti i gusti, ma si spera che aiuta chiunque fosse nella mia situazione particolare.

Problemi correlati