MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

MongoDB изчислява резултат от съществуващи полета и го поставя в ново поле в същата колекция

В зависимост от нуждите на вашето приложение можете да използвате рамката за агрегиране за изчисляване на резултата и да използвате bulkWrite() за да актуализирате колекцията си. Разгледайте следния пример, който използва $project стъпка на тръбопровод като свобода на действие за изчисления на резултата с аритметичните оператори.

Тъй като логика за изчисляване на C3 във вашия въпрос е получаване на число от 1 до 7 което е равно точно на 7 - number of points (.) , единственият възможен подход, за който мога да се сетя, е първо да съхраня допълнително поле, което съдържа тази стойност, преди да извърша агрегирането. Така че първата ви стъпка ще бъде да създадете това допълнително поле и можете да го направите с помощта на bulkWrite() както следва:

Стъпка 1:Променете схемата, за да побере допълнителни daysInWeek полето

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

В идеалния случай горната операция може също така да поеме изчисляването на другите константи във вашия въпрос и следователно създаването на Field8 като резултат. Въпреки това вярвам, че изчисления като това трябва да се правят на клиента и да оставя MongoDB да прави това, което прави най-добре на сървъра.

Стъпка 2:Използвайте агрегат, за да добавите Field8 полето

След като създадете това допълнително поле daysInWeek след това можете да конструирате тръбопровод за агрегиране, който проектира новите променливи с помощта на кохорта от аритметични оператори за извършване на изчислението (отново бихме препоръчали извършването на такива изчисления на приложния слой). Крайната проекция ще бъде продуктът на изчислените полета, които след това можете да използвате курсора на обобщения резултат, за да повторите и добавите Field8 към колекцията с всеки документ:

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

За MongoDB >= 2.6 и <= 3.0 , използвайте API за групови операции където трябва да итерирате колекцията, като използвате forEach() метод, актуализирайте всеки документ в колекцията.

Някои от аритметичните оператори от горния конвейер за агрегиране не са налични в MongoDB >= 2.6 и <= 3.0 така че ще трябва да направите изчисленията в рамките на forEach() итерация.

Използвайте груповия API, за да намалите заявките за запис на сървъра, като групирате всяка актуализация групово и изпращате до сървъра само веднъж на всеки 500 документа в колекцията за обработка:

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. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Mongoimport за обединяване/вместване на полета

  2. MongoDB агрегиране с помощта на официален C# драйвер?

  3. Актуализирайте много в mongoose

  4. Spring Boot Data и MongoDB - Filter Subdocument Array Query

  5. Какво да избера:MongoDB/Cassandra/Redis/CouchDB?