sql >> Databasteknik >  >> NoSQL >> MongoDB

MongoDB beräknar poäng från befintliga fält och lägger in det i ett nytt fält i samma samling

Beroende på dina applikationsbehov kan du använda aggregeringsramverket för att beräkna poängen och använda bulkWrite() för att uppdatera din samling. Tänk på följande exempel som använder $projekt pipeline-steg som spelrum för poängberäkningarna med aritmetiska operatorer.

Sedan logik för att beräkna C3 i din fråga får du ett nummer från 1 till 7 vilket är lika med exakt 7 - antal poäng (.) , det enda möjliga tillvägagångssättet jag kan komma på är att lagra ett extra fält som håller detta värde först innan du gör aggregeringen. Så ditt första steg skulle vara att skapa det extra fältet och du kan göra det med bulkWrite() enligt följande:

Steg 1:Ändra schemat för att ta emot extra daysInWeek fält

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

Helst kan ovanstående operation också anpassas till att beräkna de andra konstanterna i din fråga och därför skapa Field8 som ett resultat. Men jag tror att beräkningar som detta bör göras på klienten och låta MongoDB göra vad den gör bäst på servern.

Steg 2:Använd aggregering för att lägga till Fält8 fält

Efter att ha skapat det extra fältet daysInWeek du kan sedan konstruera en aggregeringspipeline som projicerar de nya variablerna med hjälp av en kohort av aritmetiska operatorer att göra beräkningen (återigen, skulle rekommendera att göra sådana beräkningar på applikationslagret). Den slutliga projektionen kommer att vara produkten av de beräknade fälten som du sedan kan använda den samlade resultatmarkören för att iterera och lägga till Fält8 till samlingen med varje 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 och <=3.0 , använd Bulk Operations API där du behöver upprepa samlingen med markörens forEach() metod, uppdatera varje dokument i samlingen.

Vissa av de aritmetiska operatorerna från ovanstående aggregeringspipeline är inte tillgängliga i MongoDB >=2.6 och <=3.0 så du måste göra beräkningarna inom forEach() iteration.

Använd bulk-API:et för att minska serverskrivbegäranden genom att bunta varje uppdatering i bulk och skicka till servern endast en gång av 500 dokument i samlingen för bearbetning:

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. Mongoose fylla underdeldokument

  2. Django MongoDB Engine-fel när tellsiteid körs

  3. Mongoose expires egendom fungerar inte korrekt

  4. Loggning med winston-mongodb och express-winston