Bạn đang bắt đầu suy nghĩ đúng hướng ở đây khi bạn đã đi đúng hướng. Thay đổi tư duy SQL của bạn, "khác biệt" thực sự chỉ là một cách viết khác của $group
hoạt động bằng một trong hai ngôn ngữ. Điều đó có nghĩa là bạn có hai hoạt động nhóm đang diễn ra ở đây và, theo thuật ngữ đường ống tổng hợp, là hai giai đoạn đường ống.
Chỉ với các tài liệu đơn giản để hình dung:
{
"campaign_id": "A",
"campaign_name": "A",
"subscriber_id": "123"
},
{
"campaign_id": "A",
"campaign_name": "A",
"subscriber_id": "123"
},
{
"campaign_id": "A",
"campaign_name": "A",
"subscriber_id": "456"
}
Đó là lý do mà đối với kết hợp "chiến dịch" đã cho, tổng số và tổng số "phân biệt" lần lượt là "3" và "2". Vì vậy, điều hợp lý cần làm là "nhóm" tất cả các giá trị "subscriber_id" đó trước và giữ nguyên số lần xuất hiện cho mỗi giá trị, sau đó suy nghĩ "đường ống", "tổng số" những giá trị đó cho mỗi "chiến dịch" và sau đó chỉ cần đếm " các lần xuất hiện riêng biệt "dưới dạng một số riêng biệt:
db.campaigns.aggregate([
{ "$match": { "subscriber_id": { "$ne": null }}},
// Count all occurrences
{ "$group": {
"_id": {
"campaign_id": "$campaign_id",
"campaign_name": "$campaign_name",
"subscriber_id": "$subscriber_id"
},
"count": { "$sum": 1 }
}},
// Sum all occurrences and count distinct
{ "$group": {
"_id": {
"campaign_id": "$_id.campaign_id",
"campaign_name": "$_id.campaign_name"
},
"totalCount": { "$sum": "$count" },
"distinctCount": { "$sum": 1 }
}}
])
Sau "nhóm" đầu tiên, các tài liệu đầu ra có thể được hình dung như thế này:
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A",
"subscriber_id" : "456"
},
"count" : 1
}
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A",
"subscriber_id" : "123"
},
"count" : 2
}
Vì vậy, từ "ba" tài liệu trong mẫu, "2" thuộc về một giá trị khác biệt và "1" thuộc về một giá trị khác. Số tiền này vẫn có thể được tính tổng bằng $sum
để có được tổng số tài liệu phù hợp mà bạn thực hiện trong giai đoạn sau, với kết quả cuối cùng:
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A"
},
"totalCount" : 3,
"distinctCount" : 2
}
Một phép tương tự thực sự tốt cho đường ống tổng hợp là đường ống unix "|" toán tử, cho phép "xâu chuỗi" các hoạt động để bạn có thể chuyển đầu ra của một lệnh tới đầu vào của lệnh tiếp theo, v.v. Bắt đầu suy nghĩ về các yêu cầu xử lý của bạn theo cách đó sẽ giúp bạn hiểu các hoạt động với đường ống tổng hợp tốt hơn.