假设我有这个模型:
const employeeSchema = new Schema({
name: String,
age: Number,
employeeData: {
department: String,
position: String,
lastTraining: Date
}
});
const Employee = mongoose.model('employee', employeeSchema);
在数据库中,唯一要保存的是看起来像这样的东西:
{
_id: ...
name: 'John Smith',
age: 40,
employeeCode: '.... '
}
发生的事情是,根据某些业务规则,来自需求主体的employeeData信息正在通过一些函数将其编译为employeeCode,并且在保存到数据库时,我只使用了employeeCode
现在,我实现此目标的方法是使用静态方法。所以,我在模型中有以下内容:
employeeSchema.statics.compileEmployeeCode = (doc) => {
if (!doc.employeeData) {
doc.employeeCode= compileCode(doc.employeeData);
delete doc.employeeData;
}
return doc;
}
然后,我需要记住,对于每次从客户端接收信息的调用,在创建文档(模型的实例)之前都要调用此函数:
const compiledDoc = Employee.compileEmployeeCode(req.body);
const employee = new Employee(comiledDoc);
我的问题是:有没有一种方法可以在我每次创建这样的文档时自动调用一些从数据中编译代码的函数,因此我不需要记住总是事先调用静态方法吗?
答案 0 :(得分:0)
Middlaware是您要寻找的。您需要创建一个函数,该函数将在架构上设置一个预保存钩子(每次保存新文档之前都会触发该钩子),并将该函数插入架构中。
function compileEmployeeCode (schema) {
schema.pre('save', next => {
if (this.employeeData) {
this.employeeCode= compileCode(this.employeeData);
delete this.employeeData;
next();
}
});
}
employeeSchema.plugin(compileEmployeeCode);
答案 1 :(得分:0)
好。确实很难,但我终于设法找到了解决方案。诀窍是在特定路径上使用setter。模式中的每个字段都是SchemaType类型,可以在其上应用一个setter: https://mongoosejs.com/docs/api.html#schematype_SchemaType-set
无论如何,如果我想让请求能够输入将转换为其他格式(例如字符串)的对象,则需要定义如下模式:
const employeeSchema = new Schema({
name: String,
age: Number,
employeeCode: {
type: String,
set: setCodeFromObj,
alias: 'employeeData'
}
});
我在这里使用的setter函数看起来像这样(我在这里省略了所有错误处理之类的内容,以保持简短:
function setCodeFromObj(v) {
const obj = {};
obj.department = v.department;
obj.position = v.position;
obj.lastTraining = v.lastTraing
// breaking the object to properties just to show that v actually includes them
return compileEmployeeCode(obj);
}
我使用别名使用户可以看到的名称不同于实际存储在数据库中的名称。我也可以使用虚拟机来做到这一点,或者只是稍微设计一下系统就可以使用相同的名称。