MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

MongoDB oblicza wynik z istniejących pól i umieszcza go w nowym polu w tej samej kolekcji

W zależności od potrzeb aplikacji możesz użyć struktury agregacji do obliczenia wyniku i użyć bulkWrite() aby zaktualizować swoją kolekcję. Rozważmy następujący przykład, który używa kodu <>$projekt krok potoku jako pole manewru dla obliczeń punktacji za pomocą operatorów arytmetycznych.

Ponieważ logika obliczania C3 w twoim pytaniu otrzymujesz numer od 1 do 7 co równa się dokładnie 7 - liczba punktów (.) , jedynym możliwym podejściem, jakie przychodzi mi do głowy, jest przechowywanie dodatkowego pola, które przechowuje tę wartość przed wykonaniem agregacji. Więc pierwszym krokiem byłoby utworzenie tego dodatkowego pola i możesz to zrobić za pomocą bulkWrite() w następujący sposób:

Krok 1:Zmodyfikuj schemat, aby pomieścić dodatkowe daysInWeek pole

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

W idealnym przypadku powyższa operacja może również uwzględniać obliczanie innych stałych w twoim pytaniu, a zatem tworzenie Pola8 w rezultacie. Uważam jednak, że takie obliczenia powinny być wykonywane na kliencie i pozwolić MongoDB robić to, co robi najlepiej na serwerze.

Krok 2:Użyj agregacji, aby dodać Pole8 pole

Po utworzeniu tego dodatkowego pola daysInWeek następnie możesz skonstruować potok agregacji, który rzutuje nowe zmienne przy użyciu kohorty operatory arytmetyczne wykonać obliczenia (znowu zalecam wykonywanie takich obliczeń na warstwie aplikacji). Ostateczna projekcja będzie iloczynem obliczonych pól, które można następnie użyć kursora zagregowanego wyniku do iteracji i dodania Pola8 do kolekcji z każdym dokumentem:

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

Dla MongoDB >=2.6 i <=3.0 , użyj interfejsu API operacji zbiorczych gdzie musisz iterować kolekcję za pomocą forEach() zaktualizuj każdy dokument w kolekcji.

Niektóre operatory arytmetyczne z powyższego potoku agregacji nie są dostępne w MongoDB >=2.6 i <=3.0 więc będziesz musiał wykonać obliczenia w forEach() iteracja.

Użyj zbiorczego interfejsu API, aby zmniejszyć liczbę żądań zapisu na serwerze, łącząc każdą aktualizację zbiorczo i wysyłając do serwera tylko raz na 500 dokumentów w kolekcji w celu przetworzenia:

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. Jak zamienić ciąg szesnastkowy na liczbę w mongodb?

  2. mongoimport CSV z pymongo

  3. Obsługa rozwijania nieistniejącego osadzonego dokumentu

  4. Czy w przypadku repliki MongoDB w zestawie z J=1 i W=Większość nadal może występować wycofywanie?

  5. Pierwsze kroki z Pythonem i MongoDB