我为用户提供了以下模型:
var UserSchema = new mongoose.Schema({
name: String,
dob: Date,
sex: String,
photo: String,
email: {type: String, index: {unique: true, required: true}},
created: {type: Date, default: Date.now}
});
var User = mongoose.model('Users', UserSchema);
如您所见,"已创建"字段采用当前日期的默认值,以便在创建新用户时自动设置。
当发布用户详细信息时,我使用以下查询:
User.findOneAndUpdate({email: user.email}, user, {upsert: true}, function (err, user) {
if (err) {
return callback (err);
} else {
callback(null, user);
}
});
将findOneAndUpdate
与upsert: true
一起使用的目的是返回现有配置文件或创建新配置文件。它还根据发布的数据更新任何字段。
但是,created
字段每次都会更新为当前日期,即使创建的字段没有过帐。如何确保此字段只设置一次?
编辑
数据库中的一个示例对象:
{
"_id" : ObjectId("54620b38b431d48bce7cab81"),
"email" : "someone@google.com",
"__v" : 0,
"name" : "somone",
"sex" : "male"
}
事实证明,即使在使用upstart创建新对象时,也没有设置created
字段。Mongoose只是根据模式返回当前日期,即使文档中不存在该日期。
因此,现在的问题变成了:如何确保使用upsert
为参数中未提供的字段创建默认值?
如果文档是用findOneAndUpdate
创建的(在查询之前不存在),并且您没有在更新中提供字段,则应使用setDefaultsInInsert为文档添加默认值。
当upsert
和setDefaultsOnInsert
都是true
时,如果找不到记录并创建了新记录,则会设置默认值。这跳过了必须检查记录是否存在的工作流程,如果不存在,则使用"保存"创建一个新记录,以确保设置了默认值。
我也遇到过同样的问题(用findOneAndUpdate
和upsert: true
创建的记录),并且字段的默认值没有添加到记录中,即使它在模式中。这只是关于在使用findOneAndUpdate
创建文档时添加默认值,而不是跳过"已创建"字段的更新。
例如
User.findOneAndUpdate({email: user.email}, user, {upsert: true, setDefaultsOnInsert:true}, ...)
findOneAndUpdate
只是发送一个MongoDB findAndModify
请求(请参阅findOneAndUpdate)。这意味着它跳过了与模式设置器、getter、默认值等相关的所有猫鼬魔法。验证只在创建/保存时运行,因此解决方法是执行.findOne()
,检查是否存在/创建一个新的.save()
。
有关的更多讨论,请参阅此问题
编辑:
关于每次更改日期的第一个问题,您可以稍微更改一下模式。去掉默认值,而是在声明模式之后添加它:
UserSchema.pre("save", function (next) {
if (!this.created) {
this.created = new Date();
}
next();
});
这只会在created:
值不存在的情况下创建一个日期,并且应该防止它每次更改创建日期(当使用.save()
时)。
请参阅Mongoose中间件