MapReduce sẽ chạy JavaScript trong một chuỗi riêng biệt và sử dụng mã bạn cung cấp để tạo và giảm các phần tài liệu của bạn để tổng hợp trên các trường nhất định. Bạn chắc chắn có thể xem bài tập dưới dạng tổng hợp trên mỗi "fieldValue". Khung tổng hợp cũng có thể làm điều này nhưng sẽ nhanh hơn nhiều vì tập hợp sẽ chạy trên máy chủ trong C ++ chứ không phải trong một chuỗi JavaScript riêng biệt. Nhưng khung tổng hợp có thể trả về nhiều dữ liệu hơn 16MB, trong trường hợp đó, bạn sẽ cần thực hiện phân vùng phức tạp hơn cho tập dữ liệu.
Nhưng có vẻ như vấn đề đơn giản hơn thế này rất nhiều. Bạn chỉ muốn tìm cho mỗi cấu hình những gì mà các cấu hình khác chia sẻ các thuộc tính cụ thể với nó - mà không cần biết kích thước của tập dữ liệu và các yêu cầu về hiệu suất của bạn, tôi sẽ giả sử rằng bạn có một chỉ mục trên fieldValues vì vậy sẽ hiệu quả hơn khi truy vấn trên đó và sau đó bạn có thể nhận được kết quả mong muốn với vòng lặp đơn giản sau:
> db.profiles.find().forEach( function(p) {
print("Matching profiles for "+tojson(p));
printjson(
db.profiles.find(
{"fieldValues": {"$in" : p.fieldValues},
"_id" : {$gt:p._id}}
).toArray()
);
} );
Đầu ra:
Matching profiles for {
"_id" : 1,
"firstName" : "John",
"lastName" : "Smith",
"fieldValues" : [
"favouriteColour|red",
"food|pizza",
"food|chinese"
]
}
[
{
"_id" : 2,
"firstName" : "Sarah",
"lastName" : "Jane",
"fieldValues" : [
"favouriteColour|blue",
"food|pizza",
"food|mexican",
"pets|yes"
]
},
{
"_id" : 3,
"firstName" : "Rachel",
"lastName" : "Jones",
"fieldValues" : [
"food|pizza"
]
}
]
Matching profiles for {
"_id" : 2,
"firstName" : "Sarah",
"lastName" : "Jane",
"fieldValues" : [
"favouriteColour|blue",
"food|pizza",
"food|mexican",
"pets|yes"
]
}
[
{
"_id" : 3,
"firstName" : "Rachel",
"lastName" : "Jones",
"fieldValues" : [
"food|pizza"
]
}
]
Matching profiles for {
"_id" : 3,
"firstName" : "Rachel",
"lastName" : "Jones",
"fieldValues" : [
"food|pizza"
]
}
[ ]
Rõ ràng là bạn có thể điều chỉnh truy vấn để không loại trừ các cấu hình đã khớp (bằng cách thay đổi {$gt:p._id}
tới {$ne:{p._id}}
và các chỉnh sửa khác. Nhưng tôi không chắc bạn sẽ nhận được giá trị bổ sung nào từ việc sử dụng khung tổng hợp hoặc bản đồ hóa vì điều này không thực sự tổng hợp một tập hợp đơn lẻ trên một trong các trường của nó (đánh giá theo định dạng của đầu ra mà bạn hiển thị). Nếu các yêu cầu về định dạng đầu ra của bạn là linh hoạt, chắc chắn bạn cũng có thể sử dụng một trong các tùy chọn tổng hợp được tích hợp sẵn.
Tôi đã kiểm tra xem điều này sẽ như thế nào nếu tổng hợp xung quanh các fieldValues riêng lẻ và nó không tệ, nó có thể giúp bạn nếu đầu ra của bạn có thể khớp với điều này:
> db.profiles.aggregate({$unwind:"$fieldValues"},
{$group:{_id:"$fieldValues",
matchedProfiles : {$push:
{ id:"$_id",
name:{$concat:["$firstName"," ", "$lastName"]}}},
num:{$sum:1}
}},
{$match:{num:{$gt:1}}});
{
"result" : [
{
"_id" : "food|pizza",
"matchedProfiles" : [
{
"id" : 1,
"name" : "John Smith"
},
{
"id" : 2,
"name" : "Sarah Jane"
},
{
"id" : 3,
"name" : "Rachel Jones"
}
],
"num" : 3
}
],
"ok" : 1
}
Về cơ bản, điều này có nghĩa là "Đối với mỗi nhóm fieldValue ($ unwind) theo fieldValue, một mảng gồm các _id và tên cấu hình phù hợp, đếm số lượng kết quả phù hợp mà mỗi trườngValue tích lũy ($ group) và sau đó loại trừ những trường chỉ có một cấu hình khớp với nó.