使用Upsert更新为true时未设置默认值

ZeM*_*oon 4 mongoose mongodb node.js mongodb-update

我为用户提供以下模型:

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);
Run Code Online (Sandbox Code Playgroud)

如您所见,“创建”字段采用当前日期的默认值,以便在创建新用户时自动设置该日期。

发布用户详细信息时,我使用以下查询:

User.findOneAndUpdate({email: user.email}, user, {upsert: true}, function (err, user) {
            if (err) {
                return callback (err);
            } else {
                callback(null, user);
            }
        });
Run Code Online (Sandbox Code Playgroud)

使用findOneAndUpdatewith 的目的upsert: true是返回一个现有的配置文件,或创建一个新的配置文件。它还根据发布的数据更新所有字段。

但是,created即使未发布创建的字段,该字段也会每次都使用当前日期进行更新。如何确保仅将该字段设置一次?

编辑

数据库中的示例对象:

{
    "_id" : ObjectId("54620b38b431d48bce7cab81"),
    "email" : "someone@google.com",
    "__v" : 0,
    "name" : "somone",
    "sex" : "male"
}
Run Code Online (Sandbox Code Playgroud)

事实证明,created即使在使用upsert创建新对象时也未设置该字段。猫鼬仅根据架构返回当前日期,即使该日期在文档中不存在。

因此,现在的问题变成了:如何确保使用using upsert为参数中未提供的字段创建默认值?

cdb*_*rin 6

findOneAndUpdate只需发送一个 MongoDBfindAndModify请求(请参阅findOneAndUpdate)。这意味着它跳过了与模式设置器、获取器、默认值等相关的所有猫鼬魔法。验证仅在创建/保存时运行,因此解决此问题的方法是执行 a .findOne(),检查存在/创建一个新的,然后然后.save()

请参阅此问题以进行更多讨论

编辑:

关于每次更改日期的第一个问题,您可以稍微更改架构。摆脱默认值,并在声明架构后添加此值:

UserSchema.pre("save", function (next) {
    if (!this.created) {
        this.created = new Date();
    }
    next();
});
Run Code Online (Sandbox Code Playgroud)

仅当该值不存在时才会创建日期created:,并且应防止每次更改创建日期(使用时.save())。

参见 Mongoose 中间件


Mih*_*scu 6

如果将默认值添加到文档中(如果它是使用findOneAndUpdate创建的(在查询之前不存在),并且未在更新中提供该字段),则应使用setDefaultsOnInsert

当upsert和setDefaultsOnInsert均为true时,如果找不到该记录并创建一个新记录,则将设置默认值。这跳过了必须检查记录是否存在以及是否不存在,然后仅通过确保设置了默认值而使用“保存”创建新记录的工作流程。

我遇到了同样的问题(使用findOneAndUpdate创建的具有upsert的记录:true),并且字段的默认值没有添加到记录中,即使它在模式中也是如此。这仅是在使用findOneAndUpdate创建文档时添加默认值,而不是为了跳过“ created”字段的更新。

即User.findOneAndUpdate({email:user.email},user,{upsert:true,setDefaultsOnInsert:true},...)