MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Come aggiornare un gran numero di documenti in MongoDB in modo più efficiente?

Se il tuo server MongoDB è 2.6 o successivo, sarebbe meglio sfruttare i comandi di scrittura API in blocco che consentono l'esecuzione di massa update operazioni che sono semplicemente astrazioni sulla parte superiore del server per semplificare la creazione di operazioni in blocco. Queste operazioni sfuse sono disponibili principalmente in due gusti:

  • Operazioni in blocco ordinate . Queste operazioni eseguono tutte le operazioni in ordine ed escono dal primo errore di scrittura.
  • Operazioni in blocco non ordinate . Queste operazioni eseguono tutte le operazioni in parallelo e aggregano tutti gli errori. Le operazioni in blocco non ordinate non garantiscono l'ordine di esecuzione.

Nota, per i server più vecchi di 2.6 l'API eseguirà la downconversion delle operazioni. Tuttavia non è possibile effettuare una conversione al 100%, quindi potrebbero esserci alcuni casi limite in cui non è possibile riportare correttamente i numeri corretti.

Per i tuoi tre casi d'uso comuni, potresti implementare l'API in blocco in questo modo:

Caso 1. Modifica il tipo di valore della proprietà, senza modificare il valore:

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();
        }); 
    } 
});

Caso 2. Aggiungi una nuova proprietà in base al valore della proprietà esistente:

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();
        }); 
    } 
});

Caso 3. Semplicemente aggiungendo proprietà di rimozione dai documenti.

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();
        }); 
    } 
});