相信大家在寫程式碼的時候,一定都會用到if/else根據不同的條件,執行不同的程式碼,有時候如果條件多一點的話,還會使用switch。

但你能相信在MongoDB資料庫的搜尋語法也使用if/else,至少剛開始接觸aggregate的我是不相信拉,直到某一次為了一個需求,我用 $bucket $facet 寫了一段很長的pipeline程式碼,還無法達到我想要的結果,向主管求助才發現有這麼好用的語法。

首先我們先介紹 $cond 這個操作符,它跟我們熟悉的if/else用法很類似,寫法有兩種格式。

// 寫法一
$cond: { 
  if: <boolean-expression>,
  then: <true-case>,
  else: <false-case> 
// 寫法二
$cond: [ <boolean-expression>, <true-case>, <false-case> ]

其中<boolean-expression>代表判斷的條件,會根據這裡的結果是true或false決定要回傳的值是<true-case>還是<false-case>

例如:商店的會員等級制度是,每年消費一定要滿3000元,才是高級會員,否則是一般會員。
原本的會員資料如下

  { id: 1, name: "小美", age: 13, sex: 1, consume: 4300 },
  { id: 2, name: "小王", age: 34, sex: 0, consume: 1400 },
  { id: 3, name: "小明", age: 25, sex: 0, consume: 0 }

此時我們可以透過以下指令來判斷,每一個人的會員等級

customer.aggregate([
    $addFields: {
      level: {
        $cond: {
          if: { $gte: ["$consume", 3000] },
          then: "高級會員",
          else: "一般會員"
  { $project: { name: 1, level: 1 } }
// 回傳的資料
  { id: 1, name: "小美", level: "高級會員" },
  { id: 2, name: "小王", level: "一般會員" },
  { id: 3, name: "小明", level: "一般會員" }

或是用以下寫法,也會得到相同的資料

customer.aggregate([
    $addFields: {
      level: {
        $cond: [{ $gte: ["$consume", 3000] }, "高級會員", "一般會員"]
  { $project: { name: 1, level: 1 } }

個人比較偏好第一種寫法,雖然在寫法上第二種方法比較簡潔,但是在閱讀上第一種方式比較好懂,尤其是對從來沒有接觸過$cond這個操作符的人,也能大概猜出這段程式碼在做什麼。

第二個要介紹的操作符是$switch,它可以根據不同條件,回傳不同的值。
例如:現在商店的會員等級制度,區分成只要註冊就是一般會員,每年消費1000元以上就是高級會員,消費3000元以上是VIP會員。

此時我們可以透過以下指令來判斷,每一個人的會員等級

customer.aggregate([
    $addFields: {
      level: {
        $switch: {
          branches: [  // branches裡面可以寫很多條件
            // case後面寫條件判斷,then後面寫當符合條件時,要回傳的值
            { case: { $gte: ["$consume", 1000] }, then: "高級會員" },
            { case: { $gte: ["$consume", 3000] }, then: "VIP會員" }
          default: "一般會員"  // 當所有條件不符合時,預設會回傳的值
  { $project: { name: 1, level: 1 } }
// 最後回傳的資料
  { id: 1, name: "小美", level: "VIP會員" },
  { id: 2, name: "小王", level: "高級會員" },
  { id: 3, name: "小明", level: "一般會員" }

ps.前面有提到$bucket$facet這兩個操作符,明後天會介紹

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