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

Zapytanie agregujące mongodb nie zwraca prawidłowej sumy przy użyciu $sum

Twój aktualny schemat zawiera marks pole typu danych jako ciąg i potrzebujesz typu danych całkowitych, aby struktura agregacji mogła obliczyć sumę. Z drugiej strony możesz użyć MapReduce do obliczenia sumy, ponieważ pozwala na użycie natywnych metod JavaScript, takich jak parseInt() we właściwościach obiektu w jego funkcjach mapy. Więc ogólnie masz dwie możliwości.

Opcja 1:Aktualizuj schemat (zmień typ danych)

Pierwszym z nich jest zmiana schematu lub dodanie innego pola w dokumencie, które ma rzeczywistą wartość liczbową, a nie reprezentację ciągu. Jeśli rozmiar dokumentu kolekcji jest stosunkowo mały, możesz użyć kombinacji kursora mongodb find() , forEach() i update() metody zmiany schematu znaków:

db.student.find({ "marks": { "$type": 2 } }).snapshot().forEach(function(doc) {
    db.student.update(
        { "_id": doc._id, "marks": { "$type": 2 } }, 
        { "$set": { "marks": parseInt(doc.marks) } }
    );
});

W przypadku stosunkowo dużych rozmiarów kolekcji wydajność bazy danych będzie niska i zaleca się użycie aktualizacje zbiorcze mongo w tym celu:

Wersje MongoDB>=2.6 i <3.2:

var bulk = db.student.initializeUnorderedBulkOp(),
    counter = 0;

db.student.find({"marks": {"$exists": true, "$type": 2 }}).forEach(function (doc) {    
    bulk.find({ "_id": doc._id }).updateOne({ 
        "$set": { "marks": parseInt(doc.marks) } 
    });

    counter++;
    if (counter % 1000 === 0) {
        // Execute per 1000 operations 
        bulk.execute(); 

        // re-initialize every 1000 update statements
        bulk = db.student.initializeUnorderedBulkOp();
    }
})

// Clean up remaining operations in queue
if (counter % 1000 !== 0) bulk.execute(); 

MongoDB w wersji 3.2 i nowszej:

var ops = [],
    cursor = db.student.find({"marks": {"$exists": true, "$type": 2 }});

cursor.forEach(function (doc) {     
    ops.push({ 
        "updateOne": { 
            "filter": { "_id": doc._id } ,              
            "update": { "$set": { "marks": parseInt(doc.marks) } } 
        }         
    });

    if (ops.length === 1000) {
        db.student.bulkWrite(ops);
        ops = [];
    }     
});

if (ops.length > 0) db.student.bulkWrite(ops);

Opcja 2:Uruchom MapReduce

Drugie podejście polegałoby na przepisaniu zapytania za pomocą MapReduce gdzie możesz użyć funkcji JavaScript parseInt() .

W swoim MapReduce operacji, zdefiniuj funkcję mapy, która przetwarza każdy dokument wejściowy. Ta funkcja mapuje przekonwertowane marks wartość ciągu do subject dla każdego dokumentu i emituje subject i przekonwertowane marks para. W tym miejscu natywna funkcja JavaScript parseInt() można zastosować. Uwaga:w funkcji this odnosi się do dokumentu, który przetwarza operacja map-reduce:

var mapper = function () {
    var x = parseInt(this.marks);
    emit(this.subject, x);
};

Następnie zdefiniuj odpowiednią funkcję zmniejszania za pomocą dwóch argumentów keySubject i valuesMarks . valuesMarks to tablica, której elementami są liczby całkowite marks wartości emitowane przez funkcję map i pogrupowane według keySubject .Funkcja zmniejsza valuesMarks tablicę do sumy jej elementów.

var reducer = function(keySubject, valuesMarks) {
    return Array.sum(valuesMarks);
};

db.student.mapReduce(
    mapper,
    reducer,
    {
        out : "example_results",
        query: { subject : "maths" }       
    }
 );

W przypadku Twojej kolekcji powyższe spowoduje umieszczenie wyniku agregacji MapReduce w nowej kolekcji db.example_results . Zatem db.example_results.find() wypisze:

/* 0 */
{
    "_id" : "maths",
    "value" : 163
}


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Natywny sterownik znaleziony z modelu Mongoose nie zwraca kursora

  2. MongoDB db.copyDatabase nie powiodło się w przypadku nieautoryzowanego dostępu

  3. Jak wykluczyć _id bez uwzględniania innych pól przy użyciu struktury agregacji?

  4. Jak zainstalować Mongodb na chipie Apple M1?

  5. Błąd indeksu MongoDB 2dsphere (nieprawidłowa geometria?)