如果在更新时属性的值为null,则不应将该属性添加到记录中

Vis*_*hal 12 javascript mongoose mongodb node.js

假设我有一个像这样的猫鼬模式:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var testSchema = new Schema({
    name: {type: String, required: true},
    nickName: {type: String}
});

var Test = module.exports = mongoose.model('Test', testSchema);
Run Code Online (Sandbox Code Playgroud)

我使用变量Test声明了CRUD操作的方法.从那一个这样的方法是更新,其定义如下:

module.exports.updateTest = function(updatedValues, callback) {

    console.log(updatedValues); //this output is shown below

    Test.update(
        { "_id": updatedValues.id },
        { "$set" : { "name" : updatedValues.name, "nickName" : updatedValues.nickName } },
        { multi: false },
        callback
    );

};
Run Code Online (Sandbox Code Playgroud)

现在,我在我的节点路由器中使用此方法,如下所示:

router.put('/:id', function(req, res, next) {

    var id = req.params.id,
    var name = req.body.name,
    var nickName = req.body.nickName

    req.checkBody("name", "Name is required").notEmpty();

    var errors = req.validationErrors();

    if(errors) { ........ }
    else {

        var testToUpdate = new Test({
            _id: id,
            name: name,
            nickName: nickName || undefined
        });

        Test.updateTest(testToUpdate, function(err, result) {
            if(err) { throw(err); }
            else { res.status(200).json({"success": "Test updated successfully"}); }
        });

    }
});
Run Code Online (Sandbox Code Playgroud)

现在如果我在数据库中保存一条新记录然后在数据库中看到它,那么它看起来像:

{
    "_id" : ObjectId("ns8f9yyuo32hru0fu23oh"), //some automatically generated id 
    "name" : "firstTest",
    "__v" : 0
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我在不更改任何内容的情况下更新同一文档,那么如果我查看数据库中的相同记录,那么我得到:

{
    "_id" : ObjectId("ns8f9yyuo32hru0fu23oh"), //some automatically generated id 
    "name" : "firstTest",
    "__v" : 0,
    "nickName" : null
}
Run Code Online (Sandbox Code Playgroud)

你能看到nickName被设置为null吗?我不希望它像这样工作.我希望如果我的属性为null,那么该属性不应该包含在记录中.

如果你还记得,我有控制台在更新之前记录了updatedValues.(参见第二个代码块).所以,这是记录的值:

{
    "_id" : ObjectId("ns8f9yyuo32hru0fu23oh"), //some automatically generated id 
    "name" : "firstTest"
}
Run Code Online (Sandbox Code Playgroud)

我不知道为什么,但是nickName不存在于记录的值中,然后在更新后我得到nickName: null.我认为,问题在于第二个代码块.你能检查一下吗?

注意:

实际上,我的架构中的字段比我指定的字段多得多.某些字段也引用其他记录.

小智 8

您可以通过在 update 方法中将 runValidators 选项设置为 true 来阻止此类文档在 MongoDB 中更新。

前任:

  module.exports.updateTest = function(updatedValues, callback) {

    Test.update(
      { "_id": updatedValues.id },
      { "$set" : { 
        "name" : updatedValues.name, "nickName" : updatedValues.nickName } ,
      },
      { multi: false, runValidators: true },
      callback
    );
  };
Run Code Online (Sandbox Code Playgroud)

此外,您还可以将选项omitUndefined设置为true以防止反映未定义的值。

前任:

  module.exports.updateTest = function(updatedValues, callback) {

    Test.update(
      { "_id": updatedValues.id },
      { "$set" : { 
        "name" : updatedValues.name, "nickName" : updatedValues.nickName } ,
      },
      { multi: false, runValidators: true, omitUndefined: true },
      callback
    );
  };
Run Code Online (Sandbox Code Playgroud)


mrB*_*rna 6

我不会这样写,但我会告诉你为什么你的代码失败了。

问题是你的 $set 块

您选择将值专门设置为传入的更新对象。如果该值是undefined您强制 mongo 将其设置为 null。

问题来了

例如,在数据库中:

{ "_id" : ObjectId("ns8f9yyuo32hru0fu23oh"), "name" : "firstTest", "nickname": "jack", "__v" : 0 }

如果你通过,testToUpdate = { name: 'foo' }你最终会得到 Test.update({ ... }, { $set: { name: 'foo', nickname: undefined }}

因为你正在updatedValues.nickname摆脱争论,而那是未定义的

你想要的是什么 Test.update({ ... }, { $set: updatedValues }翻译成Test.update({ ... }, { $set: { name: 'foo' } }.

您不再提供昵称的键,因此不会将其设置为 undefined/null。


我会使用猫鼬插件而不用担心手动将字段一直传递到您的模型

https://github.com/autolotto/mongoose-model-update

你可以定义可更新的字段,然后你就可以做

model.update(req.body) 不用担心这一切

即使您不想使用该插件,您仍然可以这样做

Test.findByIdAndUpdate(id, { name, nickname }, callback)