使用Update with Upsert为true时未设置默认值

时间:2014-11-11 12:50:57

标签: node.js mongodb mongoose 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);

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

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

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

findOneAndUpdateupsert: true一起使用的目的是返回现有的个人资料,或者创建一个新个人资料。它还会根据发布的数据更新任何字段。

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

修改

数据库中的示例对象:

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

事实证明,即使使用upsert创建新对象,也未设置created字段。 Mongoose只根据模式返回当前日期,即使它在文档中不存在。

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

2 个答案:

答案 0 :(得分:3)

findOneAndUpdate只是发送一条MongoDB findAndModify请求(请参阅findOneAndUpdate)。这意味着它会跳过涉及架构设置器,getter,默认值等的所有猫鼬魔法。验证仅在创建/保存时运行,所以解决这个问题的方法是执行.findOne(),检查存在/创建一个新的,然后是.save()

see this issue for more discussion

修改

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

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

如果created:值不存在,那只会创建一个日期,并且应该阻止它每次更改创建日期(使用.save()时)。

参见Mongoose中间件

答案 1 :(得分:3)

如果文档是使用findOneAndUpdate创建的(在查询之前它不存在),并且您没有在更新中提供字段,则应使用setDefaultsOnInsert

当upsert和setDefaultsOnInsert都为true时,如果找不到记录并创建新记录,则将设置默认值。 这会跳过必须检查记录是否存在的工作流程,如果没有,则会创建一个新的记录,并保存'只是为了确保设置默认值。

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

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