iT邦幫忙

2022 iThome 鐵人賽

DAY 10
0
自我挑戰組

被MongoDB用Aggregate暴打的後端小菜雞日記系列 第 10

被MongoDB用Aggregate暴打的後端小菜雞日記-day10-$lookup將兩個collection的資料合併(下)

  • 分享至 

  • xImage
  •  

今天延續昨天的主題,來介紹$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 }]
  }

本篇文章同步放在我的部落格,大家有空可以進來逛逛


上一篇
被MongoDB用Aggregate暴打的後端小菜雞日記-day9-$lookup將兩個collection的資料合併(上)
下一篇
被MongoDB用Aggregate暴打的後端小菜雞日記-day11- 用$sample、$rand隨機取得資料
系列文
被MongoDB用Aggregate暴打的後端小菜雞日記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言