【问题标题】:findByIdAndUpdate With Multiple Subdocuments带有多个子文档的 findByIdAndUpdate
【发布时间】:2015-11-09 10:03:04
【问题描述】:

所以我正在使用 NodeJS 和 MongoDB,并且我正在制作一个端点,让客户可以使用几个可选数据字段更新他们的用户配置文件。因此,其中一个更新查询可能如下所示:

{ 
    name: { givenName: 'first' },
    about: 'whatever',
    auth: { password: 'hashedPW' } 
}

Mongoose API 文档声明了有关 findByIdAndUpdate 的以下信息:所有不是原子操作名称的顶级更新键都被视为设置操作。

所以顶级密钥about 可以正常更新。但是,嵌套键 nameauth 会被更新值覆盖,而不仅仅是设置值。

现在我可以手动将每个字段更改为$set 键,但是有很多不同的字段,所以这样做会很烦人。是否有一种简单的方法可以将 $set 规则也应用于子文档?即将语句转换成这个,带有猫鼬选项或其他东西:

{ 
    $set : { name: { givenName: 'first' } },
    $set : { about: 'whatever' },
    $set : { auth: { password: 'hashedPW' } } 
}

【问题讨论】:

  • 您通常应该能够将完整对象添加为第二个参数...
  • 根据文档的措辞,我认为情况并非如此;我认为它仅适用于顶级密钥。 mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate
  • 我没有电脑自动取款机,所以无法测试。大多数时候我使用 update 而不是 findByIdAndUpdate 并且适用于嵌套键。
  • $set 已经被猫鼬默认使用了。但为防止覆盖嵌入字段,请使用点表示法:{'name.givenName': 'first',... }
  • @hassansin 因为我试图使它成为一个全面的“更新”端点,所以我想从字面上获取输入,并将其应用于猫鼬,而不需要用户以 Mongo 风格制定他们的查询细绳。有没有办法将 javascript 对象转换为可以工作的点表示法?

标签: node.js mongodb mongoose mongodb-query


【解决方案1】:

您基本上需要将输入对象转换为"dot notation" 形式,以避免在更新中覆盖其他可能的子键。这真的很简单:

var obj = { 
    name: { givenName: 'first' },
    about: 'whatever',
    auth: { password: 'hashedPW' } 
};

var target = {};

function dotNotate(obj,prefix) {
  prefix = (typeof(prefix) === 'undefined') ? "" : prefix;
  Object.keys(obj).forEach(function(key) {
    if ( typeof(obj[key]) === "object" ) {
      dotNotate(obj[key],key + ".")
    } else {
      target[prefix + key] = obj[key];
    }
  });
}

dotNotate(obj);

现在target 对象如下所示:

{
    "name.givenName" : "first",
    "about" : "whatever",
    "auth.password" : "hashedPW"
}

所以你的语句的更新块只是写成:

{ "$set": target }

作为参考,dotNotate() 函数可以更加精致和独立。还包括较短的默认分配作为有效输入通常被认为是“真实的”。此外,应该在每次调用之前添加“前缀”,以使这项工作在任意深度:

function dotNotate(obj,target,prefix) {
  target = target || {},
  prefix = prefix || "";

  Object.keys(obj).forEach(function(key) {
    if ( typeof(obj[key]) === "object" ) {
      dotNotate(obj[key],target,prefix + key + ".");
    } else {
      return target[prefix + key] = obj[key];
    }
  });

  return target;
}

然后你可以使用内联:

var update = { "$set": dotNotate(obj) };

如果您愿意,也可以像这样传入一个已定义的对象:

var update = { "$set": {} };
dotNotate(obj,update["$set"]);

结果相同。

也适用于数组和嵌套深度:

{
    "things" : [
        {
            "a" : 1,
            "b" : 2
        },
        {
            "a" : 3,
            "b" : 4
        }
    ],
    "bool" : false
}

有输出:

{
    "things.0.a" : 1,
    "things.0.b" : 2,
    "things.1.a" : 3,
    "things.1.b" : 4,
    "bool" : false
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2014-09-26
    • 2023-03-26
    • 1970-01-01
    • 2015-07-18
    • 2013-08-14
    • 1970-01-01
    相关资源
    最近更新 更多