我正在使用 mongoose 創建一個新檔案,我回傳的新創建的檔案包含ALL THE FIELDS,包括我在架構中標記為{ select: false }的那些。
很奇怪,對吧?
作為參考,每當我使用任何 Model.find()、Model.findOne() 等命令時,這些標記的欄位都不會按預期回傳。
所以對我來說,這種在創建時回傳所有欄位的行為很奇怪......
難道 { select: false } 只適用于查找操作?
無論如何,所以我的問題是,成功創建后如何取回“干凈”檔案?
或者,如果由于某種原因無法做到這一點,是否有一個內置的 mongoose 函式可以根據模型的模式清除所有 { select: false } 欄位?
示例模型:
const { Schema, model } = require('mongoose');
const userSchema = new Schema({
nickname: { type: String, required: true },
email: { type: String, required: true },
myHiddenField: { type: String, required: true, select: false },
});
const UserModel = model('user', userSchema);
module.exports = UserModel;
檔案創建:
// Way number 1: using save
// const user = new UserModel({ nickname: "hello", email: "world", myHiddenField: "bluh bluh" });
// const userResult = (await user.save()).toObject();
// Way number 2: using save
const userResult = (await UserModel.create({ nickname: "hello", email: "world", myHiddenField: "bluh bluh" })).toObject();
return userResult;
上面的兩個創建表單中的任何一個都會創建一個用戶檔案,并帶回一個包含我的隱藏欄位的檔案。
uj5u.com熱心網友回復:
這是一個很好的問題,我以前沒有遇到過。
正如@Charchit_Kapoor 所提到的,保存功能不使用模式來構建投影,因此您必須在保存后進行,并且由于貓鼬提供了“發布”中間件 - 似乎它是正確的地方。
這是一個完整的解決方案供您使用:
const { Schema, model } = require('mongoose');
// Step 1: create a new schema
const userSchema = new Schema({
nickname: { type: String, required: true },
email: { type: String, required: true },
myHiddenField: { type: String, required: true, select: false },
someObject: { type:
{
a: { type: Number },
b: { type: Boolean, select: false },
c: { type: String },
}, required: true
},
});
// Step 2: create a mongoose 'post' middleware
userSchema.post('save', (doc) => {
const docObj = doc.toObject();
const checkPropertiesRecursively = (objWithProperties, subObject) => {
const keys = Object.keys(objWithProperties);
for (let i = 0; i < keys.length; i ) {
const curProperty = objWithProperties[keys[i]];
if (curProperty.select === false) {
delete subObject[keys[i]];
} else if (typeof curProperty.type === 'object') {
checkPropertiesRecursively(curProperty.type, subObject[keys[i]]);
}
}
};
checkPropertiesRecursively(userSchemaTemplate, docObj);
return docObj;
});
// Step 3: create a Model from the schema
const User = model('user', userSchema);
module.exports = User;
代碼說明
- 自動化功能
在 'post' 中間件中,我創建了一個函式,用于掃描您的模式以查找您未選擇的欄位,并為您洗掉它們。您可能在想“為什么不使用“delete object.key”手動洗掉它們?我知道這些欄位是什么!”。
雖然這是真的,但最好是自動為您完成。正如您可能知道的那樣,模型會發生變化,今天未被選中的,可能是明天被選中的,反之亦然。因此,當這種情況發生時,您只想更新一個地方,而不是兩個。在這種情況下,那個地方就是架構。
- 遞回函式
我知道有些人正在為遞回而苦苦掙扎,所以我會用簡單的外行術語來表達:你舉了一個只有頂級欄位的模式示例,對吧?但是如果它還包含一個物件欄位呢?該物件欄位還將包含欄位,其中一些可以選擇內部欄位,而有些則不能。因此,這只是為了涵蓋您的基礎知識,以處理稍微復雜的情況。請注意,在我給出的模式示例中,有一個名為 someObject 的額外欄位,具有 3 個內部欄位:a、b、c。我將 b 標記為未選中,因此遞回函式將捕獲并洗掉它。公平起見?我在這里缺少對包含物件的 Array 型別欄位的處理,但您可以在遞回中以相同的方式處理它。
- 在創建模型之前宣告帖子
正如貓鼬的檔案所述:
“在編譯模型后呼叫 pre() 或 post() 通常在 Mongoose 中不起作用”。
意思是,userSchema.post('save', fn)必須在 const User = model('user', userSchema); 之前。
否則, post('save') 中間件不會觸發。
- 回傳檔案
請注意,在中間件的末尾,我將回傳更改后的檔案。這個很重要!否則你不會享受你辛勤作業的成果。
uj5u.com熱心網友回復:
您可以使用 ,post上的中間件save來清理您的檔案,如下所示:
schema.post('save', (doc) => {
delete doc.myHiddenField;
});
這是必需的,因為Mongoose在保存時會按原樣回傳檔案,就像它被發送到 MongoDB 一樣。但是,在find函式的情況下,它會根據模式生成一個投影并將其發送到 MongoDB。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/512268.html
