MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Comment mettre à jour un grand nombre de documents dans MongoDB le plus efficacement ?

Si votre serveur MongoDB est 2.6 ou plus récent, il serait préférable d'utiliser une commande d'écriture API de masse qui permettent l'exécution en masse de update opérations qui sont simplement des abstractions au-dessus du serveur pour faciliter la création d'opérations en bloc. Ces opérations groupées se présentent principalement sous deux formes :

  • Opérations groupées ordonnées . Ces opérations exécutent toutes les opérations dans l'ordre et génèrent une erreur à la première erreur d'écriture.
  • Opérations groupées non ordonnées . Ces opérations exécutent toutes les opérations en parallèle et agrègent toutes les erreurs. Les opérations en bloc non ordonnées ne garantissent pas l'ordre d'exécution.

Notez que pour les serveurs plus anciens que 2.6, l'API convertira les opérations. Cependant, il n'est pas possible de convertir à 100 %, il peut donc y avoir des cas extrêmes où il ne peut pas rapporter correctement les bons chiffres.

Pour vos trois cas d'utilisation courants, vous pouvez implémenter l'API de transfert en masse comme ceci :

Cas 1. Changer le type de valeur de la propriété, sans changer la valeur :

var MongoClient = require('mongodb').MongoClient;

MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
    // Handle error
    if(err) throw err;

    // Get the collection and bulk api artefacts
    var col = db.collection('users'),           
        bulk = col.initializeOrderedBulkOp(), // Initialize the Ordered Batch
        counter = 0;        

    // Case 1. Change type of value of property, without changing the value.        
    col.find({"timestamp": {"$exists": true, "$type": 2} }).each(function (err, doc) {

        var newTimestamp = parseInt(doc.timestamp);
        bulk.find({ "_id": doc._id }).updateOne({
            "$set": { "timestamp": newTimestamp }
        });

        counter++;

        if (counter % 1000 == 0 ) {
            bulk.execute(function(err, result) {  
                // re-initialise batch operation           
                bulk = col.initializeOrderedBulkOp();
            });
        }
    });

    if (counter % 1000 != 0 ){
        bulk.execute(function(err, result) {
            // do something with result
            db.close();
        }); 
    } 
});

Cas 2. Ajouter une nouvelle propriété en fonction de la valeur de la propriété existante :

MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
    // Handle error
    if(err) throw err;

    // Get the collection and bulk api artefacts
    var col = db.collection('users'),           
        bulk = col.initializeOrderedBulkOp(), // Initialize the Ordered Batch
        counter = 0;        

    // Case 2. Add new property based on value of existing property.        
    col.find({"name": {"$exists": false } }).each(function (err, doc) {

        var fullName = doc.firstname + " " doc.lastname;
        bulk.find({ "_id": doc._id }).updateOne({
            "$set": { "name": fullName }
        });

        counter++;

        if (counter % 1000 == 0 ) {
            bulk.execute(function(err, result) {  
                // re-initialise batch operation           
                bulk = col.initializeOrderedBulkOp();
            });
        }
    });

    if (counter % 1000 != 0 ){
        bulk.execute(function(err, result) {
            // do something with result
            db.close();
        }); 
    } 
});

Cas 3. Ajouter simplement des propriétés de suppression de documents.

MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
    // Handle error
    if(err) throw err;

    // Get the collection and bulk api artefacts
    var col = db.collection('users'),           
        bulk = col.initializeOrderedBulkOp(), // Initialize the Ordered Batch
        counter = 0;        

    // Case 3. Simply adding removing properties from documents.    
    col.find({"street_no": {"$exists": true } }).each(function (err, doc) {

        bulk.find({ "_id": doc._id }).updateOne({
            "$set": { "no": doc.street_no },
            "$unset": { "street_no": "" }
        });

        counter++;

        if (counter % 1000 == 0 ) {
            bulk.execute(function(err, result) {  
                // re-initialise batch operation           
                bulk = col.initializeOrderedBulkOp();
            });
        }
    });

    if (counter % 1000 != 0 ){
        bulk.execute(function(err, result) {
            // do something with result
            db.close();
        }); 
    } 
});