sql >> Base de Datos >  >> NoSQL >> MongoDB

MongoDB calcula el puntaje de los campos existentes y lo coloca en un nuevo campo en la misma colección

Dependiendo de las necesidades de su aplicación, puede usar el marco de agregación para calcular la puntuación y usar bulkWrite() para actualizar tu colección. Considere el siguiente ejemplo que usa el código <>$proyecto paso de canalización como margen de maniobra para los cálculos de puntuación con los operadores aritméticos.

Dado que la lógica para calcular C3 en su pregunta está obteniendo un número de 1 a 7 que equivale exactamente a 7 - número de puntos (.) , el único enfoque factible que se me ocurre es almacenar un campo adicional que contenga este valor antes de realizar la agregación. Entonces, su primer paso sería crear ese campo adicional y puede hacerlo usando el bulkWrite() de la siguiente manera:

Paso 1:Modifique el esquema para acomodar daysInWeek adicionales 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, la operación anterior también puede acomodar el cálculo de las otras constantes en su pregunta y, por lo tanto, crear el Field8 como resultado. Sin embargo, creo que se deben realizar cálculos como este en el cliente y dejar que MongoDB haga lo que mejor hace en el servidor.

Paso 2:Use el agregado para agregar Field8 campo

Habiendo creado ese campo adicional daysInWeek luego puede construir una tubería de agregación que proyecte las nuevas variables utilizando una cohorte de operadores aritméticos para hacer el cálculo (nuevamente, recomendaría hacer tales cálculos en la capa de aplicación). La proyección final será el producto de los campos calculados que luego puede usar el cursor de resultado agregado para iterar y agregar Field8 a la colección con cada 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); }

Para MongoDB >=2.6 y <=3.0 , use la API de operaciones masivas donde necesita iterar la colección usando el cursor paraCada() método, actualice cada documento de la colección.

Algunos de los operadores aritméticos de la canalización de agregación anterior no están disponibles en MongoDB >=2.6 y <=3.0 por lo que deberá realizar los cálculos dentro del paraCada() iteración.

Use la API masiva para reducir las solicitudes de escritura del servidor al agrupar cada actualización de forma masiva y enviar al servidor solo una vez cada 500 documentos en la colección para su procesamiento:

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