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

MongoDB calcola il punteggio dai campi esistenti e lo inserisce in un nuovo campo nella stessa raccolta

A seconda delle esigenze della tua applicazione, puoi utilizzare il framework di aggregazione per calcolare il punteggio e utilizzare il bulkWrite() per aggiornare la tua collezione. Considera il seguente esempio che utilizza il $project passaggio della pipeline come margine per il calcolo del punteggio con gli operatori aritmetici.

Poiché la logica per il calcolo di C3 nella tua domanda sta ottenendo un numero da 1 a 7 che è esattamente 7 - number of points (.) , l'unico approccio fattibile che mi viene in mente è archiviare un campo aggiuntivo che contenga questo valore prima di eseguire l'aggregazione. Quindi il tuo primo passo sarebbe creare quel campo extra e puoi farlo usando il bulkWrite() come segue:

Passaggio 1:modifica lo schema per ospitare daysInWeek extra campo

var counter = 0, bulkUpdateOps = [];

db.collection1.find({
    "Field5": { "$exists": true }
}).forEach(function(doc) {
    // calculations for getting the number of points in Field5
    var points, daysInWeek;
    points = (doc.Field5.match(new RegExp(".", "g")) || []).length;
    daysInWeek = 7 - points;
    bulkUpdateOps.push({
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": {
                "$set": { "daysInWeek": daysInWeek }
            }
        }
    });
    counter++;

    if (counter % 500 == 0) {
        db.collection1.bulkWrite(bulkUpdateOps);
        bulkUpdateOps = [];
    }
});

if (counter % 500 != 0) { db.collection1.bulkWrite(bulkUpdateOps); }

Idealmente l'operazione di cui sopra può anche consentire il calcolo delle altre costanti nella tua domanda e quindi la creazione del Field8 di conseguenza. Tuttavia, credo che calcoli come questo dovrebbero essere eseguiti sul client e lasciare che MongoDB faccia ciò che sa fare meglio sul server.

Passaggio 2:utilizza l'aggregato per aggiungere Field8 campo

Dopo aver creato quel campo extra daysInWeek è quindi possibile costruire una pipeline di aggregazione che proietta le nuove variabili utilizzando una coorte di operatori aritmetici per eseguire il calcolo (di nuovo, consiglierei di eseguire tali calcoli sul livello dell'applicazione). La proiezione finale sarà il prodotto dei campi calcolati che puoi quindi utilizzare il cursore del risultato aggregato per scorrere e aggiungere Field8 alla raccolta con ogni documento:

var pipeline = [
        {
            "$project": {
                "C1": {
                    "$add": [ 
                        10, 
                        { "$multiply": [ "$Field3", 0.03 ] } 
                    ]
                },
                "C2": {
                    "$cond": [
                        { "$eq": [ "$Field2", 1 ] }, 
                        1, 
                        0.03 
                    ]
                },
                "C3": "$daysInWeek",
                "C4": {
                    "$cond": [
                        { "$eq": [ "$Field2", 1 ]  },
                        { "$pow": [ "$Field4", -0.6 ] },
                        1
                    ]
                }
            }
        },
        {
            "$project": {
                "Field8": { "$multiply": [ "$C1", "$C2", "$C3", "$C4" ] }
            }
        }
    ],
    counter = 0,
    bulkUpdateOps = [];

db.collection1.aggregate(pipeline).forEach(function(doc) {
    bulkUpdateOps.push({
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": {
                "$set": { "Field8": doc.Field8 }
            }
        }
    });
    counter++;

    if (counter % 500 == 0) {
        db.collection1.bulkWrite(bulkUpdateOps);
        bulkUpdateOps = [];
    }
});

if (counter % 500 != 0) { db.collection1.bulkWrite(bulkUpdateOps); }

Per MongoDB >= 2.6 e <= 3.0 , utilizza l'API per le operazioni in blocco dove è necessario iterare la raccolta utilizzando forEach() metodo, aggiornare ogni documento nella raccolta.

Alcuni degli operatori aritmetici della pipeline di aggregazione sopra non sono disponibili in MongoDB >= 2.6 e <= 3.0 quindi dovrai eseguire i calcoli all'interno di forEach() iterazione.

Utilizza l'API in blocco per ridurre le richieste di scrittura del server raggruppando ogni aggiornamento in blocco e inviando al server solo una volta ogni 500 documenti nella raccolta per l'elaborazione:

var bulkUpdateOps = db.collection1.initializeUnorderedBulkOp(),
    cursor = db.collection1.find(), // cursor 
    counter = 0;

cursor.forEach(function(doc) {
    // computations
    var c1, c2, c3, c4, Field8;
    c1 = 10 + (0.03*doc.Field3);
    c2 = (doc.Field2 == 1) ? 1: 0.03;
    c3 = 7 - (doc.Field5.match(new RegExp(".", "g")) || []).length;
    c4 = (doc.Field2 == 1) ? Math.pow(doc.Field, -0.6) : 1;
    Field8 = c1*c2*c3*c4;

    bulkUpdateOps.find({ "_id": doc._id }).updateOne({
        "$set": { "Field8": Field8 }
    });

    if (counter % 500 == 0) {
        bulkUpdateOps.execute();
        bulkUpdateOps = db.collection1.initializeUnorderedBulkOp();
    }
})

if (counter % 500 != 0) { bulkUpdateOps.execute(); }