【问题标题】:add property to nested array in mongodb document向 mongodb 文档中的嵌套数组添加属性
【发布时间】:2011-07-19 22:05:31
【问题描述】:

我有一个具有以下结构的 mongodb 文档

> db.user.find().limit(1);
{ "_id" : "1", "foo" : { "bars" : [
    {
        "name" : "bar1"
    },
    {
        "name" : "bar2"
    },
], ... }, ... }

我想为每个bar 添加一个新属性。我的脚本在 bars 数组上进行了迭代,但我无法在其中获取新属性,我该怎么做?

var users = db.user.find({"foo.bars":{$exists:true}});

users.forEach(function(user) {
    user.foo.bars.forEach(function(bar)
    {
       printjson(bar);
       //how can I specify the current 'bar' in this update?
       //db.experience.update({_id: user._id}, {$set: {"what goes here?" : "newbarValue"}});
    });
});

【问题讨论】:

  • 您确定“要为每个条形添加新属性”确实有效吗?尤其是你想要在 {"user.foo.bars.${bar} 中使用 'user' 做什么?'${bar}' 应该做什么?可能是你试图发明新语法而没有检查如何事情真的有效吗?
  • "user.foo.bars.${bar}" 是指示性的——它不是有效的语法,你会注意到它被注释掉了。我试图表达我的意图。

标签: javascript mongodb mongo-shell


【解决方案1】:

传道人如是说:

var users = db.user.find({"foo.bars":{$exists:true}});

users.forEach(function(user) {
    var id = user._id;

    var foo_bars = user.foo.bars;
    var new_foo_bars = [];

    for(var i = 0; i < foo_bars.length; i++) {
        var foo_bar = foo_bars[i];
        foo_bar['newkey'] = 'newvalue';
        new_foo_bars.push(foo_bar);
    }

    db.user.update({"_id":id}, {$set:{"foo.bars":new_foo_bars}});
});

【讨论】:

  • AFAIK,使用 forEach 不能很好地扩展,只要更新运行它就会锁定整个数据库。
  • 很好的答案,但有没有办法避免使用 foreach ?我正在使用上述方法从另一个集合中检索变量,并将其添加到集合的结果集中,然后再呈现模板。在 sql 中,我会通过 id 进行连接,mongo 有类似的东西吗?
【解决方案2】:

我注意到您正在 JS 中滚动浏览客户端的数组。

如果您要从旧数组中形成一个新的“bars”数组,然后将其作为一个全新的值推入,这意味着您只需进行一次 DB 调用,并且代码非常优雅。

如果 MongoDB 通常不支持它,最好只在客户端完成工作。

【讨论】:

  • 正确 - 您可以在其中一个数组元素下添加单个项目,其中 $set 不是所有元素。客户端也是如此。您可以通过 localhost 在服务器上运行客户端脚本,然后它应该会执行得很好。
【解决方案3】:

您必须单独更新嵌套文档的每个元素。使用位置运算符 '$' 将不起作用,因为它仅适用于第一个匹配项(如文档所述)。

【讨论】:

  • 这里什么没用?你不能这样做。
  • “您必须单独更新嵌套文档的每个元素。”本质上是我要问的问题 - 将其重新作为答案是没有用的。将我指向相关文档或提供一行伪代码会很棒。在来这里之前花了一个小时试图解决这个问题 - 所以我很失望它被否决并建议我还没有尝试用 doco 自行解决。
  • 你可以在数组 $set 操作中使用硬索引。所以 db.user.update({_id: user._id}, {$set: {'foo.bars.0.someValue' : "newbarValue"}}) 有效。如果我正确理解您的问题,您所要做的就是用您在内部 for 循环中增加的计数器替换 0。
  • @Remon。谢谢,这是个好建议。如果我在那里硬编码一个索引,就像你说的那样它确实有效,但是当我尝试在该字符串中使用变量索引或提取一个变量时,我似乎无法让 update(...) 工作构建“foo.bars”。 + i + ".someValue" 并在 update(...) 函数中使用该变量。
  • 是的,你不能在 JS 中做到这一点(或者至少我也不知道怎么做,不是专家)我不认为,但这只是 shell 中的一个问题,或者如果你使用节点。大多数其他语言都可以做到这一点。
猜你喜欢
  • 1970-01-01
  • 2018-08-31
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
  • 2015-06-04
  • 2020-06-27
  • 2017-04-28
  • 2019-10-09
相关资源
最近更新 更多