今天延續昨天的主題,來介紹$lookup
進階的用法,在做join的同時,使用pipeline整理、計算資料。
假設現在我們有顧客(customer)的基本資料
{ id: 1, name: " 小美", age: 13, sex: 1 },
{ id: 2, name: " 小王", age: 34, sex: 0 },
{ id: 3, name: " 小明", age: 25, sex: 0 }
以及他們各自的購買紀錄(order)
{ id: 1, customer_id: 2, consume: 1200, date: "2022-01-08T06:12:03Z" },
{ id: 2, customer_id: 1, consume: 4300, date: "2022-03-18T06:12:03Z" },
{ id: 3, customer_id: 2, consume: 200, date: "2022-05-01T06:12:03Z" },
{ id: 4, customer_id: 3, consume: 8200, date: "2022-07-15T06:12:03Z" },
{ id: 5, customer_id: 3, consume: 200, date: "2022-08-12T06:12:03Z" }
如果想要計算2022上半年每位顧客的消費總額,我們可以下這樣的指令
customer.aggregate([
{
$lookup: {
from: "order", // 從哪一張資料表join資料
// 類似用let宣告一個參數,並給定一個值
// 前面是參數名稱(可以自訂,後面要使用必須在前面寫$$)
// 後面是設定參數的值,是原本的collection與join的collection相等的欄位
let: { customer_id: "$id" },
pipeline: [
{
$match: {
$expr: {
$and: [
// 還必須在確認兩張colloction是哪個欄位相等,不然撈到的資料會是全部
{ $eq: ["$customer_id", "$$customer_id"] },
{ $gte: ["$date", "2022-01-01T00:00:00Z"] },
{ $lte: ["$date", "2022-06-30T23:59:59Z"] }
]
}
}
},
{ $group: { _id: "$customer_id", total_consume: { $sum: "$consume" } } }
],
as: "consume" // 這些資料會新增在一個欄位內,as要填就是該欄位的名稱
}
}
]);
其中在pipeline裡面的計算,寫法和之前寫的aggregate pipeline幾乎一模一樣,也是在陣列內寫入一連串的指令,搜尋、整理計算資料,再傳給下一個pipeline運行。
比較需要注意的地方是,pipeline第一個一定要寫$match
取選擇要join資料的選擇條件,以及$match
裡面一定要再用$expr
這個操作符,來寫條件判斷,裡面可以用$and
加入多個條件判斷。
此外在$expr
語法上得寫法和之前寫的不太一樣,如果還是用以前的寫法,會無法正確跑出想要的結果。
// 以前寫只有$match的寫法
{
$match: {
customer_id: 2,
date: {
$gte: "2022-01-01T00:00:00Z",
$lte: "2022-06-30T23:59:59Z"
}
}
}
// 現在$match裡面多使用$expr的寫法
{
$match: {
$expr: {
$and: [
{ $eq: ["$customer_id", "$$customer_id"] },
{ $gte: ["$date", "2022-01-01T00:00:00Z"] },
{ $lte: ["$date", "2022-06-30T23:59:59Z"] }
]
}
}
}
更詳細的說明,請參考$lookup的官方文件說明
最後我們可以得到aggregate pipeline運算的結果是
{
id: 1,
name: " 小美",
age: 13,
sex: 1,
consume: [{ _id: 1, total_consume: 4300 }]
},
{
id: 2,
name: " 小王",
age: 34,
sex: 0,
consume: [{ _id: 1, total_consume: 1400 }]
},
{
id: 3,
name: " 小明",
age: 25,
sex: 0,
consume: [{ _id: 1, total_consume: 0 }]
}
本篇文章同步放在我的部落格,大家有空可以進來逛逛