點燈坊

失くすものさえない今が強くなるチャンスよ

如何將兩個 Result Set 合併 ?

Sam Xiao's Avatar 2021-10-22

實務上有時必須對兩個以上 Table 做 Query,將結果合併後再傳回,由於 Knex 回傳為 Promise,該如何將這兩個 Promise 合併呢 ?

Version

Knex 0.20.3

Async Await

let f = async _ => {
  let books1 = await mySQL ('books').where ('price', '>', 200)
  let books2 = await mySQL ('books').where ('price', '<=', 200)

  return books1.concat (books2)
}

由於 Knex 回傳 Promise,若搭配 await 解構後成為 Array,因此可使用 Array.prototype.concat() 將兩個 Array 加以合併。

由於使用了 await,因次 function 必須宣告為 async 再轉為 Promise。

Promise.all

let f = _ => {
  let books1 = mySQL ('books').where ('price', '>', 200)
  let books2 = mySQL ('books').where ('price', '<=', 200)

  return Promise.all ([books1, books2]).then (flatten)
}

由於 Knex 回傳為 Promise,至於這兩個 Promise 誰先完成很難說,要視資料量與網路速度決定,因此使用了 Promise.all 等兩個 Promise 都完成後才合併,算是 asynchronous 版本的 Array.prototype.concat()

不過 Promise.all 的結果為兩層 Array,因此還必須透過 Ramda 的 flatten 打平後才是我們要的結果。

merge000

Conclusion

  • 由本文可發現 Promise 在 ECMAScript 有兩種處理方式,await 會將值從 Promise 轉為正常值,就可繼續使用 imperative 寫法,最後再使用 async 回傳 Promise;而 Promise 系列方法則透過 then 提供 function 針對 Promise 內部資料處理,最後直接回傳 Promise,屬於 FP 風格
  • 由於 then 要求傳入 function,可善用 Ramda 的 function 或自行組合 function 傳入

Reference

Ramda, flatten()