findOneAndUpdate覆盖作为doc传递的2+级深层对象中的属性

时间:2015-05-16 17:03:07

标签: node.js mongoose

假设我有这个架构:

var UserSchema = new Schema({
    name : {
        firstName : String,
        lastName : String
    }
});

我创建了这个用户:

User.create({
    name : {
        firstName : Bob,
        lastName : Marley
    }
}, function (err, user) {
    if(err) {
        return console.error(err);
    } else {
        return console.log(user);
    }
});

我注意到如果我这样做:

User.findOneAndUpdate({_id: userId}, { name: { firstName : "Damian" } }, function (err, user) {
    if(err) {
        return console.error(err);
    } else {
        return console.log(user);
    }
});

我的用户现在是:

user = {
    name : {
        firstName : "Damian"
    }
}

但是,如果我这样做:

User.findOneAndUpdate({_id: userId}, { "name.firstName" : "Damian" }, function (err, user) {
    if(err) {
        return console.error(err);
    } else {
        return console.log(user);
    }
});

我的用户是:

user = {
    name : {
        firstName : "Damian",
        lastName : "Marley"
    }
}

有没有办法将一个没有填充所有属性的对象传递给findOneAndUpdate,并保留之前的属性,而不删除它们? (与Mongo中的$set功能相同)。这真烦人......

2 个答案:

答案 0 :(得分:5)

使用flat展平您不完整的嵌套对象,如下所示:

findOneAndUpdate

现在,您可以像在第二个示例中一样调用std::string contobin(std::string str) { std::string result; for(int i=0; i<str.size(); ++i) for(int j=8; j--;) { result.append((1<<j) & uint8_t(str[i]) ? "1" : "0"); } return result; }

答案 1 :(得分:2)

如果您将实际的完整嵌套对象传递给findOneAndUpdate()(或任何其他mongoose更新方法):

Model.findOneAndUpdate({ ... }, {
  name: {
    firstName : "Damian"
  }
})

您将覆盖整个(嵌套)对象,因此从文档中删除所有其他属性(在本例中为lastName)。

要仅更新嵌套对象的特定属性,而不是整个对象,则需要使用嵌套属性的完整路径。

{ "name.firstName" : "Damian" }

(这将使嵌套的lastName对象中的name保持不变)

但是,每当您更新嵌套对象的属性时,手动处理它都会很烦人。

幸运的是,压平您传递给findOneAndUpdate()的更新对象根本不是问题 - 所以它永远不会超过一个级别。

有很多方法可以解决这个问题:Fastest way to flatten / un-flatten nested JSON objects

最快的解决方案似乎是使用现成的flat Node.js库。

var flatten = require('flat')

User.findOneAndUpdate(
  { _id: userId },
  // same as passing '{ "name.firstName": "Damian" }':
  flatten({
    name: {
      firstName : "Damian"
    }
  }), function (err, user) {
  if(err) {
    return console.error(err);
  } else {
    return console.log(user);
  }
});