iT邦幫忙

2022 iThome 鐵人賽

DAY 15
0
自我挑戰組

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

被MongoDB用Aggregate暴打的後端小菜雞日記-day15-$merge 將資料寫回資料庫

  • 分享至 

  • xImage
  •  

當你好不容易寫好一連串的aggregate,想要將整理好的資料寫回資料庫內,這時候就可以使用$merge將資料寫入,使用上必須特別注意,一定要放在pipeline最後一個位置,不然會直接噴錯誤訊息,「MongoError: $merge can only be the final stage in the pipeline」。

讓我們延續昨天的範例,原本有學生的成績資料(隔壁小王成績太高,有被我調低一點XD)

  { _id: 1, name: " 小美", math: 20, english: 12 },
  { _id: 2, name: " 小王", math: 81, english: 66 },
  { _id: 3, name: " 小明", math: 78, english: 30 },
  { _id: 4, name: " 小帥", math: 80, english: 60 },
  { _id: 5, name: " 小真", math: 78, english: 12 }

老師決定幫學生進行加分,加分方式是數學成績乘上1.2,英文的分數乘上1.5,並且要將調整完的分數,寫回去資料庫內,這時會使用到以下指令。

student.aggregate([
  {
    $addFields: {
      math: { $floor: { $multiply: ["$math", 1.2] } },
      english: { $floor: { $multiply: ["$english", 1.5] } }
    }
  },
  {
    $merge: {
      into: "student",  // 要將結果寫入哪一個collection內
      on: "_id", // 寫入的資料,要用哪一個欄位與原始資料做對應
      whenMatched: "replace", // 如果有原始資料,則取代它
      whenNotMatched: "insert"  // 如果沒有原始資料,則新增一筆資料
    }
  },
]);

此時aggregate跑完會回傳空陣列,如果想看資料是否被正確寫入,可以使用find把學生的資料撈出來檢查一下。

student.find() // 找出student collection所有資料

// 回傳的資料會是
  { _id: 1, name: " 小美", math: 24, english: 18 },
  { _id: 2, name: " 小王", math: 97, english: 99 },
  { _id: 3, name: " 小明", math: 93, english: 45 },
  { _id: 4, name: " 小帥", math: 96, english: 90 },
  { _id: 5, name: " 小真", math: 93, english: 18 }

$merge其實有很多細節設定可以拿出來講

  1. 如果into設定要寫入的collection是原本不存在的,MongoDB會自動幫你建立一個新的collection
  2. on其實可以設定多個欄位,來取匹配原本資料庫的文件,看要取代掉哪一筆資料。

例如:on: ["_id", "name]代表寫入的資料_idname這兩個欄位都要和原本資料_idname欄位值都相同,才會取代這筆資料,否則會新增一筆全新資料。

⚠️ 必須特別注意的是,選取的欄位一定要有 unique index,不然終端機會噴出錯誤訊息「MongoError: Cannot find index to verify that join fields will be unique」

ps.良心建議,直接寫on: "_id"會比較間單,因為MongoDB本身就會幫你建立好_id的unique index,完全不需要額外設定。(本人為了測時這個設定,被unique index搞了一整個上午)

  1. whenMatched除了replace(取代),還有其他的設定可以選擇,例如:keepExisting可以保留原本的資料,不會被取代。
  2. whenNotMatched除了insert(插入),還有其他的設定可以選擇,例如:discard不會插入新的資料進入collection。

如果想要在更深入了解$merge的細節設定,可以參考官方文件

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


上一篇
被MongoDB用Aggregate暴打的後端小菜雞日記-day14-$facet 一次使用多個pipeline
下一篇
被MongoDB用Aggregate暴打的後端小菜雞日記-day16-陣列操作符(上)
系列文
被MongoDB用Aggregate暴打的後端小菜雞日記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言