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

MongoDB beregner score fra eksisterende felter og sætter det i et nyt felt i samme samling

Afhængigt af dine applikationsbehov kan du bruge aggregeringsrammen til at beregne scoren og bruge bulkWrite() for at opdatere din samling. Overvej følgende eksempel, som bruger $projekt pipeline-trin som spillerum for scoreberegningerne med de aritmetiske operatorer.

Siden logik til beregning af C3 i dit spørgsmål får du et nummer fra 1 til 7 som er lig med 7 - antal point (.) , den eneste gennemførlige tilgang, jeg kan komme i tanke om, er at gemme et ekstra felt, der har denne værdi, før du foretager aggregeringen. Så dit første skridt ville være at oprette det ekstra felt, og du kan gøre det ved hjælp af bulkWrite() som følger:

Trin 1:Rediger skemaet for at rumme ekstra daysInWeek felt

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

Ideelt set kan ovenstående operation også rumme at beregne de andre konstanter i dit spørgsmål og derfor oprette Field8 som resultat. Jeg mener dog, at beregninger som denne bør udføres på klienten og lade MongoDB gøre, hvad den gør bedst på serveren.

Trin 2:Brug aggregeret til at tilføje Field8 felt

Efter at have oprettet det ekstra felt daysInWeek du kan derefter konstruere en aggregeringspipeline, der projicerer de nye variabler ved hjælp af en kohorte af aritmetiske operatorer at udføre beregningen (vil igen anbefale at udføre sådanne beregninger på applikationslaget). Den endelige projektion vil være produktet af de beregnede felter, som du derefter kan bruge den samlede resultatmarkør til at iterere og tilføje Field8 til samlingen med hvert 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); }

For MongoDB >=2.6 og <=3.0 , brug Bulk Operations API hvor du skal gentage samlingen ved hjælp af markørens forEach() metode, skal du opdatere hvert dokument i samlingen.

Nogle af de aritmetiske operatorer fra ovenstående aggregeringspipeline er ikke tilgængelige i MongoDB >=2.6 og <=3.0 så du bliver nødt til at udføre beregningerne i forEach() iteration.

Brug masse-API'en til at reducere serverskriveanmodninger ved at samle hver opdatering i bulk og kun sende til serveren én gang for hver 500 dokumenter i samlingen til behandling:

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. Aggregerede rammer kan ikke bruge indekser

  2. Nogen måde at få det modificerede IDS fra mongodbs bulkoperationer ved hjælp af mongoose?

  3. Fjern kun ét dokument i MongoDB

  4. Mongo DB-fejl:ugyldig operator:$search ved $tekstsøgning