MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

truy vấn tổng hợp mongodb không trả về số tiền thích hợp khi sử dụng $ sum

Lược đồ hiện tại của bạn có các dấu marks kiểu dữ liệu trường dưới dạng chuỗi và bạn cần kiểu dữ liệu số nguyên cho khung tổng hợp của mình để tính tổng. Mặt khác, bạn có thể sử dụng MapReduce để tính tổng vì nó cho phép sử dụng các phương thức JavaScript gốc như parseInt() trên các thuộc tính đối tượng của bạn trong các chức năng bản đồ của nó. Vì vậy, tổng thể bạn có hai sự lựa chọn.

Tùy chọn 1:Cập nhật giản đồ (Thay đổi loại dữ liệu)

Đầu tiên là thay đổi lược đồ hoặc thêm một trường khác trong tài liệu của bạn có giá trị số thực tế không phải là biểu diễn chuỗi. Nếu kích thước tài liệu bộ sưu tập của bạn tương đối nhỏ, bạn có thể sử dụng kết hợp con trỏ của mongodb find() , forEach() update() các phương pháp để thay đổi giản đồ điểm của bạn:

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

Đối với kích thước bộ sưu tập tương đối lớn, hiệu suất db của bạn sẽ chậm và bạn nên sử dụng cập nhật hàng loạt mongo cho điều này:

Phiên bản MongoDB> =2.6 và <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 phiên bản 3.2 và mới hơn:

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

Tùy chọn 2:Chạy MapReduce

Cách tiếp cận thứ hai là viết lại truy vấn của bạn bằng MapReduce nơi bạn có thể sử dụng hàm JavaScript parseInt() .

Trong MapReduce của bạn hoạt động, xác định chức năng bản đồ xử lý từng tài liệu đầu vào. Hàm này ánh xạ các dấu marks đã chuyển đổi giá trị chuỗi cho subject cho mỗi tài liệu và phát ra subject và chuyển đổi các dấu marks đôi. Đây là nơi chứa hàm gốc JavaScript parseInt() có thể ứng tuyển. Lưu ý:trong hàm, this đề cập đến tài liệu mà thao tác thu nhỏ bản đồ đang xử lý:

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

Tiếp theo, xác định hàm giảm tương ứng với hai đối số keySubjectvaluesMarks . valuesMarks là một mảng có các phần tử là các dấu marks các giá trị do hàm bản đồ phát ra và được nhóm bởi keySubject . Hàm làm giảm valuesMarks mảng thành tổng các phần tử của nó.

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

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

Với bộ sưu tập của bạn, phần trên sẽ đưa kết quả tổng hợp MapReduce của bạn vào một bộ sưu tập mới db.example_results . Do đó, db.example_results.find() sẽ xuất:

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


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Lọc bỏ các mảng trùng lặp và trả về mảng duy nhất trong tổng hợp mongodb

  2. Chỉ mục duy nhất không hoạt động với Mongoose / MongoDB

  3. Số lượng tài liệu sai trong cụm phân đoạn MongoDB

  4. GridFS trong Spring Data MongoDB

  5. Lưu trữ null so với hoàn toàn không lưu trữ khóa trong MongoDB