在 Sails 中,模型定義的最上層屬性稱為 模型設定。這包括從屬性定義,到模型將使用的資料庫設定,以及一些其他選項。
本頁的大部分內容致力於完整導覽 Sails 支援的模型設定。但在我們開始之前,讓我們先看看如何在 Sails 應用程式中實際應用這些設定。
模型設定允許您自訂 Sails 應用程式中模型的行為。它們可以針對每個模型指定,方法是在模型定義中設定最上層屬性,或在 sails.config.models
中設定應用程式範圍的預設值。
若要修改應用程式中所有模型共用的預設模型設定,請編輯 config/models.js
。
例如,當您產生新的應用程式時,Sails 會自動在您的 config/models.js
檔案中包含三個不同的預設屬性:id
、createdAt
和 updatedAt
。假設您希望所有模型都使用稍微不同的自訂 id
屬性。若要執行此操作,您只需在 config/models.js
定義中覆寫 attributes: { id: {...} }
即可。
若要進一步自訂特定模型的這些設定,您可以將它們指定為該模型定義檔案(例如 api/models/User.js
)中的最上層屬性。這將覆寫具有相同名稱的預設模型設定。
例如,如果您將 fetchRecordsOnUpdate: true
新增至其中一個模型定義 (api/models/UploadedFile.js
),則該模型現在將傳回已更新的記錄。但您應用程式的其餘模型將不受影響:它們仍將使用預設設定(即 fetchRecordsOnUpdate: false
,除非您已變更)。
在您的日常開發中,您最常互動的模型設定是 attributes
。屬性幾乎在每個模型定義中都會使用,並且某些預設屬性包含在 config/models.js
中。為了方便日後參考,以下是一些額外提示
tableName
,您應始終針對每個模型執行此操作。(應用程式範圍的表格名稱沒有意義!)datastore
設定——例如,如果您的預設資料儲存區是 PostgreSQL,但您有一個 CachedBloodworkReport
模型想要放在 Redis 中。migrate
和 schema
設定指定為應用程式範圍的預設值,永遠不要針對每個模型指定。現在您已經了解模型設定是什麼以及如何設定它們,讓我們瀏覽並查看每個設定。
模型的屬性定義集。
attributes: { /* ... */ }
類型 | 範例 | 預設 |
---|---|---|
請參閱下方。 | {} |
大多數時候,您會在個別模型定義(在 api/models/
中)中定義屬性,但您也可以在 config/models.js
中指定預設屬性。這可讓您在一個位置定義一組全域屬性,然後依靠 Sails 使它們隱含地提供給您的所有模型,而無需重複自己。預設屬性也可以透過在相關模型定義中定義具有相同名稱的替換屬性,針對每個模型進行覆寫。
attributes: {
id: { type: 'number', autoIncrement: true },
createdAt: { type: 'number', autoCreatedAt: true },
updatedAt: { type: 'number', autoUpdatedAt: true },
}
如需模型屬性的完整介紹,包括如何在您的 Sails 應用程式中定義和使用它們,請參閱概念 > ORM > 屬性。
一個函式,可讓您自訂模型的記錄序列化為 JSON 的方式。
customToJSON: function() { /*...*/ }
類型 | 範例 | 預設 |
---|---|---|
請參閱下方。 | 不適用 |
將 customToJSON
設定新增至模型會變更模型記錄字串化的方式。換句話說,它可讓您注入自訂邏輯,在這些記錄的其中一筆傳遞至 JSON.stringify()
時執行。這最常用於實作安全機制,確保使用者密碼等敏感資料不會意外包含在回應中(因為 res.send()
和 actions2 可能會在傳送之前將資料字串化)。
customToJSON
函式不接受任何引數,但提供將記錄作為 this
變數存取的功能。這可讓您省略敏感資料並傳回已清理的結果,JSON.stringify()
在產生 JSON 字串時實際上會使用該結果。例如
customToJSON: function() {
// Return a shallow copy of this record with the password and ssn removed.
return _.omit(this, ['password', 'ssn'])
}
customToJSON 函式設計為不支援非同步功能。這可讓核心中的同步位元保持同步,並為系統整體提供更好的穩定性。
請注意,
customToJSON
中可用的this
變數是實際記錄物件的直接參考,因此請小心不要修改它。換句話說,請避免撰寫類似delete this.password
的程式碼。相反地,請使用類似_.omit()
或_.pick()
的方法來取得記錄的副本。或者,只需建構新的字典並傳回該字典(例如return { foo: this.foo }
)。
SQL 表格 (/MongoDB 集合) 的名稱,模型將在此處將其記錄儲存和擷取為列 (/MongoDB 文件)。
tableName: 'some_preexisting_table'
類型 | 範例 | 預設 |
---|---|---|
'some_preexisting_table' |
與模型的識別項相同。 |
tableName 設定可讓您自訂特定模型應使用的基礎實體模型的名稱。換句話說,它可讓您控制模型在資料庫中儲存和擷取記錄的位置,而不會影響控制器動作/輔助程式中的程式碼。
預設情況下,Sails 會使用模型的識別項來判斷其表格名稱
await User.find();
// => SELECT * FROM user;
這是建議的慣例,在大多數情況下不需要變更。但是,如果您與使用不同平台(例如 Python 或 C#)編寫的現有應用程式共用舊版資料庫,或者您的團隊偏好資料庫表格的不同命名慣例,則自訂此對應可能會很有用。
回到上面的範例,如果您在 api/models/User.js
中修改了模型定義,並設定 tableName: 'foo_bar'
,那麼您會看到稍微不同的結果
await User.find();
// => SELECT * FROM foo_bar;
tableName
中有什麼?在 MySQL 和 PostgreSQL 等資料庫中,此設定是指字面意義的「表格」。在 MongoDB 中,它指的是「集合」。這實際上只是關於熟悉度:我們稱之為「表格」的任何其他詞語也會查詢。
Sails 每次載入應用程式時將執行的自動移轉策略。
migrate: 'alter'
類型 | 範例 | 預設 |
---|---|---|
'alter' |
系統會提示您。 注意:在生產環境中,這始終為 'safe' 。 |
migrate
設定控制您應用程式的自動移轉策略。簡而言之,這會告知 Sails 您是否希望它嘗試自動重建資料庫中的表格/集合/集/等等。
在開發應用程式的過程中,您幾乎總是需要對資料庫的結構進行至少一到兩次重大變更。什麼構成「重大變更」取決於您使用的資料庫:例如,假設您將新屬性新增至其中一個模型定義。如果該模型設定為使用 MongoDB,那麼這沒什麼大不了的;您可以像什麼都沒發生一樣繼續開發。但如果該模型設定為使用 MySQL,則有一個額外的步驟:必須將資料行新增至對應的表格(否則模型方法(例如 .create()
)將停止運作)。因此,對於使用 MySQL 的模型,新增屬性是對資料庫結構描述的重大變更。
即使您的所有模型都使用 MongoDB,仍有一些重大的結構描述變更需要注意。例如,如果您將
unique: true
新增至其中一個屬性,則必須在 MongoDB 中建立唯一索引。
在 Sails 中,關於資料庫移轉有兩種不同的操作模式
sails run
手動執行所有資料庫移轉。每當您需要將重大變更套用至您的生產資料庫時,都應使用手動資料庫移轉。否則,當您在筆記型電腦上開發或執行自動化測試時,自動移轉可以為您節省大量時間。
當您在開發環境中啟動 Sails 應用程式時(例如,在全新的 Sails 應用程式中執行 sails lift
),將執行設定的自動移轉策略。如果您使用 migrate: 'safe'
,則不會發生任何額外的事情,但如果您使用 drop
或 alter
,Sails 會將您開發資料庫中的每筆記錄載入記憶體,然後捨棄並重新建立資料的實體層表示(即表格/集合/集/等等)。這可讓您在模型定義中進行的任何重大變更(例如移除唯一性條件約束)自動套用至您的開發資料庫。最後,如果您使用 alter
,Sails 接著會嘗試使用它稍早儲存的記錄重新植入新產生的表格/集合/集。
自動移轉策略 | 說明 |
---|---|
safe |
永不自動移轉我的資料庫。我將手動執行。 |
alter |
自動移轉資料行/欄位,但嘗試保留我現有的資料(實驗性) |
drop |
抹除/捨棄所有我的資料,並在每次我啟動 Sails 時重建模型 |
請記住,當使用
alter
或drop
策略時,您自上次啟動應用程式以來對資料庫所做的任何手動變更都可能會遺失。這包括自訂索引、外部索引鍵條件約束、資料行順序和註解等項目。一般而言,自動移轉建立的表格不保證在您的實體資料庫資料行的任何細節方面保持一致,除了設定資料行名稱、類型(包括字元集/編碼,如果已指定)和唯一性之外。
Sails 中的 drop
和 alter
自動移轉策略作為一項功能存在,目的是為了在您開發期間以及執行自動化測試時提供便利。它們並非設計用於您關心的資料。請注意,永遠不要將 drop
或 alter
與生產資料集搭配使用。事實上,作為協助您避免意外執行此操作的安全機制,無論您設定了什麼,每當您在生產環境中啟動應用程式時,Sails *始終*使用 migrate: 'safe'
。
在許多情況下,託管提供者會在偵測到 Node.js 應用程式時自動設定 NODE_ENV
環境變數為「生產」。即便如此,請不要僅依賴該安全機制,並採取通常的預防措施來保護您使用者的資料安全。每當您將 Sails(或任何其他工具或架構)連線到具有預先存在的生產資料的資料庫時,請執行試執行,尤其是第一次。生產資料是敏感的、有價值的,並且在許多情況下是無法取代的。客戶、使用者及其律師不樂見它被清除。
最佳實務是,確保永遠不要在您 100% 確定您在生產環境中執行時啟動或部署您的應用程式,並使用生產資料庫認證。在組織範圍內大規模解決此問題的常見方法是,簡單地永遠不要將生產資料庫認證推送至您的原始碼儲存庫,而是依靠環境變數來取得所有敏感認證。(如果您的應用程式受法規要求約束,或者如果大量人員可以存取您的程式碼庫,則這尤其是一個好主意。)
如果您正在處理相對大量的開發/測試資料,則 alter
自動移轉策略可能需要很長時間才能在啟動時完成。如果您注意到類似 npm test
、sails console
或 sails lift
的命令似乎掛起,請考慮減少您的開發資料集的大小。(請記住:Sails 自動移轉僅應在您的本機筆記型電腦/桌上型電腦上使用,並且僅適用於小型開發資料集。)
模型是否期望記錄符合一組特定的屬性。
schema: true
類型 | 範例 | 預設 |
---|---|---|
true |
取決於配接器。 |
schema
設定可讓您在「無結構描述」或「有結構描述」模式之間切換模型。更具體地說,它控制類似 .create()
和 .update()
等方法的行為。通常,只要您使用的配接器支援,您就可以在記錄中儲存任意資料。但是,如果您啟用 schema:true
,則只會實際儲存與模型的 attributes
對應的屬性。
此設定僅與使用無結構描述資料庫(例如 MongoDB)的模型相關。當連接到關聯式資料庫(例如 MySQL 或 PostgreSQL)時,模型始終有效地為
schema:true
,因為基礎資料庫只能在預先設定的表格和資料行中儲存資料。
資料儲存區設定的名稱,模型將使用該設定來尋找記錄、建立記錄等。
datastore: 'legacyECommerceDb'
類型 | 範例 | 預設 |
---|---|---|
'legacyECommerceDb' |
'default' |
這可讓您指示此模型將擷取和儲存其資料的資料庫。除非另有指定,否則您應用程式中的每個模型都使用名為「預設」的內建資料儲存區,該資料儲存區包含在每個新的 Sails 應用程式中。這讓您可以輕鬆設定應用程式的主要資料庫,同時仍允許您覆寫任何特定模型的 datastore
設定。
如需有關設定應用程式資料儲存區的詳細資訊,請參閱參考 > 設定 > 資料儲存區。
一組用於解密資料的金鑰。除非另行設定,否則預設資料加密金鑰(或「DEK」)始終用於加密。
dataEncryptionKeys: {
default: 'tVdQbq2JptoPp4oXGT94kKqF72iV0VKY/cnp7SjL7Ik='
}
除非您的使用案例需要金鑰輪換,否則
default
金鑰是您需要的全部。除了default
之外的任何其他資料加密金鑰都僅用於解密使用它們加密的舊資料。
若要停用資料加密金鑰,您需要為其提供新的金鑰 ID(例如 2028
),然後建立新的 default
金鑰以用於任何新的加密。例如,如果您在 2028 年發行 Sails 應用程式,並且您的金鑰每年輪換,那麼次年您的 dataEncryptionKeys
可能會如下所示
dataEncryptionKeys: {
default: 'DZ7MslaooGub3pS/0O734yeyPTAeZtd0Lrgeswwlt0s=',
'2028': 'C5QAkA46HD9pK0m7293V2CzEVlJeSUXgwmxBAQVj+xU='
}
在在那之後的 2030 年 1 月更換預設金鑰之後,您可能會得到
dataEncryptionKeys: {
default: 'tVdQbq2JptoPp4oXGT94kKqF72iV0VKY/cnp7SjL7Ik=',
'2029': 'DZ7MslaooGub3pS/0O734yeyPTAeZtd0Lrgeswwlt0s=',
'2028': 'C5QAkA46HD9pK0m7293V2CzEVlJeSUXgwmxBAQVj+xU='
}
在您使用此模型呼叫 .destroy()
時,是否要始終表現得像您設定了 cascade: true
一樣。
cascadeOnDestroy: true
類型 | 範例 | 預設 |
---|---|---|
true |
false |
預設情況下,基於效能考量,這會停用。您可以使用此模型設定啟用它,或使用.meta({cascade: true})
針對每個查詢啟用它。
此功能僅適用於
sails-mongo
配接器。
如果設定為 true
,則模型將不會使用自動產生的 MongoDB ObjectID 物件作為其主索引鍵。這可讓您使用 sails-mongo
配接器建立模型,其主索引鍵是任意字串或數字,而不僅僅是長長的 UUID 樣式的物件。請注意,將此設定為 true
表示您必須在每次呼叫 .create()
或 .createEach()
時提供 id
的值。
類型 | 範例 | 預設 |
---|---|---|
true |
false |
預設情況下,基於效能考量,這會停用。您可以使用此模型設定啟用它,或使用.meta({dontUseObjectIds: true})
針對每個查詢啟用它。
以下低階設定包含在完整性的精神中,但在實務上,它們應該很少(甚至從未)變更。
模型的主索引鍵屬性的名稱。
您永遠不需要變更此設定。相反地,如果您需要使用自訂主索引鍵,請在「id」屬性上設定自訂
columnName
。
primaryKey: 'id'
類型 | 範例 | 預設 |
---|---|---|
'id' |
'id' |
按照慣例,這是「id」,一個預設屬性,它會自動包含在 Sails v1.0 開始產生之新應用程式的 config/models.js
檔案中。變更模型主索引鍵的最佳方法是簡單地自訂該預設屬性的 columnName
。
例如,假設您有一個 User 模型需要與預先存在的 MySQL 資料庫中的表格整合。該表格可能有一個名稱不是「id」(例如「email_address」)的資料行作為其主索引鍵。若要讓您的模型尊重該主索引鍵,您會在模型定義中為您的 id
屬性指定覆寫;如下所示
id: {
type: 'string',
columnName: 'email_address',
required: true
}
然後,在您應用程式的程式碼中,您將能夠依主索引鍵查閱使用者,同時自動為您處理所有產生的 SQL 查詢中到 email_address
的對應
await User.find({ id: req.param('emailAddress' });
拋開所有警告不談,假設您是 MongoDB 的狂熱使用者。在您的新 Sails 應用程式中,您將從在
config/models.js
中預設的「id」屬性上設定columnName: '_id'
開始。然後,您可以像平常一樣使用 Sails 和 Waterline,一切都會運作良好。但是,如果您發現自己希望可以為了熟悉度而變更「id」屬性本身的實際名稱呢?這樣,當您在程式碼中呼叫內建模型方法時,您將使用類似
.destroy({ _id: 'ba8319abd-13810-ab31815' })
的語法,而不是通常的「id」。這就是此模型設定可能變得有用的地方。您所要做的就是編輯
config/models.js
,使其包含primaryKey: '_id'
,然後將預設的「id」屬性重新命名為「_id」。但是,有一些充分的理由重新考慮此行動方案。
模型的唯一小寫識別項。
模型的
identity
是唯讀的。它是自動衍生的,永遠不應手動設定。
Something.identity;
類型 | 範例 |
---|---|
'purchase' |
在 Sails 中,模型的 identity
會透過將其檔案名稱轉換為小寫並去除檔案副檔名來自動推斷。例如,api/models/Purchase.js
的識別項將為 purchase
。它可以作為 sails.models.purchase
存取,如果藍圖路由已啟用,您將能夠使用類似 GET /purchase
和 PATCH /purchase/1
的請求來存取它。
assert(Purchase.identity === 'purchase');
assert(sails.models.purchase.identity === 'purchase');
assert(Purchase === sails.models.purchase);
模型唯一的全域識別項,它也決定了其對應全域變數的名稱(如果相關)。
模型的
globalId
是唯讀的。它是自動衍生的,永遠不應手動設定。
Something.globalId;
類型 | 範例 |
---|---|
'Purchase' |
模型 globalId 的主要目的是決定 Sails 自動代表其公開的全域變數的名稱——也就是說,除非模型的全域化已停用。在 Sails 中,模型的 globalId
會從其檔案名稱自動推斷。例如,api/models/Purchase.js
的 globalId 將為 Purchase
。
assert(Purchase.globalId === 'Purchase');
assert(sails.models.purchase.globalId === 'Purchase');
if (sails.config.globals.models) {
assert(sails.models.purchase === Purchase);
}
else {
assert(typeof Purchase === 'undefined');
}