MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

MongoDB berechnet die Punktzahl aus vorhandenen Feldern und fügt sie in ein neues Feld in derselben Sammlung ein

Abhängig von Ihren Anwendungsanforderungen können Sie das Aggregations-Framework zur Berechnung der Punktzahl verwenden und die bulkWrite() um Ihre Sammlung zu aktualisieren. Betrachten Sie das folgende Beispiel, das den Code $projekt Pipeline-Schritt als Spielraum für die Score-Berechnungen mit den arithmetischen Operatoren.

Seit Logik zur Berechnung von C3 In Ihrer Frage erhalten Sie eine Nummer von 1 bis 7 was genau 7 - Anzahl der Punkte (.) entspricht , ist der einzig mögliche Ansatz, den ich mir vorstellen kann, ein zusätzliches Feld zu speichern, das diesen Wert enthält, bevor die Aggregation durchgeführt wird. Ihr erster Schritt wäre also, dieses zusätzliche Feld zu erstellen, und Sie können dies mit bulkWrite() wie folgt:

Schritt 1:Ändern Sie das Schema, um zusätzliche daysInWeek aufzunehmen Feld

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

Idealerweise kann die obige Operation auch die Berechnung der anderen Konstanten in Ihrer Frage berücksichtigen und somit das Field8 erstellen als Ergebnis. Ich glaube jedoch, dass Berechnungen wie diese auf dem Client durchgeführt werden sollten und MongoDB auf dem Server das tun lassen sollte, was es am besten kann.

Schritt 2:Verwenden Sie Aggregat, um Field8 hinzuzufügen Feld

Nachdem Sie dieses zusätzliche Feld daysInWeek erstellt haben Sie können dann eine Aggregationspipeline erstellen, die die neuen Variablen mithilfe einer Kohorte von projiziert arithmetische Operatoren um die Berechnung durchzuführen (wiederum würde ich empfehlen, solche Berechnungen auf der Anwendungsschicht durchzuführen). Die endgültige Projektion ist das Produkt der berechneten Felder, die Sie dann mit dem Aggregatergebnis-Cursor durchlaufen und Field8 hinzufügen können zur Sammlung mit jedem Dokument:

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

Für MongoDB >=2.6 und <=3.0 verwenden Sie die API für Massenoperationen wo Sie die Sammlung mit dem des Cursors durchlaufen müssen forEach() -Methode jedes Dokument in der Sammlung aktualisieren.

Einige der arithmetischen Operatoren aus der obigen Aggregationspipeline sind in MongoDB >=2.6 nicht verfügbar und <=3.0 Sie müssen also die Berechnungen im durchführen forEach() Iteration.

Verwenden Sie die Bulk-API, um Server-Schreibanforderungen zu reduzieren, indem Sie jede Aktualisierung in großen Mengen bündeln und nur einmal alle 500 Dokumente in der Sammlung zur Verarbeitung an den Server senden:

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