sql >> Database >  >> NoSQL >> MongoDB

MongoDB berekent de score van bestaande velden en plaatst deze in een nieuw veld in dezelfde verzameling

Afhankelijk van uw toepassingsbehoeften, kunt u het aggregatieraamwerk gebruiken voor het berekenen van de score en de bulkWrite() om uw collectie bij te werken. Overweeg het volgende voorbeeld dat de $project pijplijnstap als speelruimte voor de scoreberekeningen met de rekenkundige operatoren.

Sinds logica voor het berekenen van C3 in uw vraag krijgt u een nummer van 1 tot 7 wat precies gelijk is aan 7 - aantal punten (.) , de enige haalbare benadering die ik kan bedenken, is om een ​​extra veld op te slaan dat deze waarde eerst bevat voordat de aggregatie wordt uitgevoerd. Dus je eerste stap zou zijn om dat extra veld aan te maken en je kunt dit doen met de bulkWrite() als volgt:

Stap 1:Wijzig het schema om extra daysInWeek op te vangen veld

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

In het ideale geval kan de bovenstaande bewerking ook de berekening van de andere constanten in uw vraag mogelijk maken en daarom het Veld8 maken als resultaat. Ik ben echter van mening dat dergelijke berekeningen op de client moeten worden gedaan en MongoDB moet laten doen wat het het beste kan op de server.

Stap 2:gebruik aggregatie om Field8 toe te voegen veld

Dat extra veld daysInWeek . hebben gemaakt je kunt dan een aggregatiepijplijn construeren die de nieuwe variabelen projecteert met behulp van een cohort van rekenkundige operatoren om de berekening uit te voeren (nogmaals, zou aanbevelen om dergelijke berekeningen op de applicatielaag uit te voeren). De uiteindelijke projectie is het product van de berekende velden die u vervolgens kunt gebruiken met de cursor voor het geaggregeerde resultaat om te herhalen en Field8 toe te voegen. naar de collectie bij elk document:

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

Voor MongoDB >=2.6 en <=3.0 , gebruik de Bulk Opeartions API waar je de verzameling moet herhalen met de cursor forEach() methode, werkt u elk document in de verzameling bij.

Sommige rekenkundige operatoren uit de bovenstaande aggregatiepijplijn zijn niet beschikbaar in MongoDB >=2.6 en <=3.0 dus je moet de berekeningen uitvoeren binnen de forEach() iteratie.

Gebruik de bulk-API om schrijfverzoeken van de server te verminderen door elke update in bulk te bundelen en slechts één keer op de 500 documenten in de verzameling naar de server te verzenden voor verwerking:

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


  1. Mongodb-fout kan tekstindex niet gebruiken om te voldoen aan $text-query

  2. Kan MongoDB niet starten als een service

  3. Hoe tel ik alle documenten in een verzameling en gebruik ik de inhoud in een controller, met MongoDB en Express.js?

  4. MongoDB en MongoJS - kan runCommand niet laten werken voor tekstquery's