Node Sequelize Update 與 Set 的差異
主要遇到的問題
原專案是使用 Rails
開發,但因總總原因,決定改用 Node.js
開發,但在轉換時,遇到了一些問題,其中就有 Sequelize 的 Update 與 Set 的差異。
使用 Rails
所提供的 ORM 有跟很方便的方法,就是可以把 column 設定為 json
或是 text
,在寫入與讀取時,ORM 會自動幫你處理,可以很方便的讀寫 json 裡的資料。但在 Node.js
使用 Sequelize 時,就沒有這麼方便了。
以 Sequelize
的做法,不管是讀取 json
或是 yaml
是必都必須有個 Parser 與 Loader 把這些資料轉成 Attribute。
範例而言:
(這只是範例,一般來說應該要照著 RDBMS
的規範來設計資料表)
const { Sequelize, DataTypes } = require("sequelize");
const sequelize = new Sequelize("sqlite::memory:");
const User = sequelize.define("User", {
// JSON
data: {
type: DataTypes.JSON,
allowNull: false,
defaultValue: {},
},
age: {
type: DataTypes.VIRTUAL,
get() {
return jsonLoader(this.getDataValue("data"), 'age');
},
set(value) {
const data = this.getDataValue("data");
jsonParser(data, { age: value });
},
},
sex: {
type: DataTypes.VIRTUAL,
get() {
return jsonLoader(this.getDataValue("data"), 'sex').
},
set(value) {
const data = this.getDataValue("data");
jsonParser(data, { sex: value });
},
}
});
在這個狀況下,如果使用 Update
進行更新某個欄位:
// 原本 User: { data: { age: 18, sex: 'male' } }
await User.update({ age: 20 }, { where: { id: 1 } });
最後在 DB 所看到的資料是:
{
"age": 20
}
問題出在於 Update
沒有把整個資料拿出來,所以在更新時 this.getDataValue("data")
是空的。
而 Set
的做法是:
const user = await User.findByPk(1);
user.set({ age: 20 }).save();
因為已經把整個資料給讀取出來,所以 this.getDataValue("data")
是有資料的,這樣就可以正確的更新資料了。
結論
其實在 RDBMS
使用上,還是盡量依照規範來設計資料表,不要把 json
或是 yaml
放在一個欄位裡,這樣會讓資料難以維護,也不利於查詢。但如果真的需要使用 json
或是 yaml
,就要注意在更新時,要把整個資料拿出來,不然會有資料遺但如果真的需要使用 json
或是 yaml
,就要注意在更新時,要把整個資料拿出來,不然會有資料遺失的問題。