MongoDB:删除多个对象

时间:2015-09-08 09:58:57

标签: mongodb mongodb-query

我试图删除分类在多个键内的对象内的项目。 例如,从每个项目部分删除ObjectId(" c")

这是结构:

    {
      "somefield" : "value",
      "somefield2" : "value",
      "objects" : {
        "/" : {
           "color" : "#112233",
           "items" : [ 
             ObjectId("c"),
             ObjectId("b")
          ]
        },
        "/folder1" : {
           "color" : "#112233",
           "items" : [
             ObjectId("c"),
             ObjectId("d")
          ]
        },
        "/folder2" : {
           "color" : "112233",
           "items" : []
        },
        "/testing" : {
           "color" : "112233",
           "items" : [ 
             ObjectId("c"), 
             ObjectId("f")
          ]
       }
     }
    }

我尝试拉和未设置如下:

    db.getCollection('col').update(
      {},
      { $unset: { 'objects.$.items': ObjectId("c") } },
      { multi: true }
    )

    db.getCollection('col').update(
      {},
      { "objects": {"items": { $pull: [ObjectId("c")] } } },
      {  multi: true }
    )

有什么想法吗?谢谢!

2 个答案:

答案 0 :(得分:2)

这里的问题很大程度上取决于文档的当前结构。 MongoDB不能遍历路径"以一种有效的方式,你的结构目前有一个"对象" ('对象')已命名"键"。这意味着访问"项目"在每个"键"需要每个键的显式路径才能看到该元素。这里没有通配符:

 db.getCollection("coll").find({ "objects./.items": Object("c") })

这是"匹配"的基本原则。你无法做到的事情"所有的钥匙"没有导致JavaScript代码,这真的很糟糕。

更改结构。而不是"对象键",使用"数组"相反,像这样:

{
   "somefield" : "value",
   "somefield2" : "value",
   "objects" : [
      {
        "path": "/", 
        "color" : "#112233",
        "items" : [ 
            "c",
            "b"
        ]
      },
      {
        "path": "/folder1",
        "color" : "#112233",
        "items" : [
            "c",
            "d"
        ]
      },
      {
        "path": "/folder2",
        "color" : "112233",
        "items" : []
      },
      {
        "path": "/testing",
        "color" : "112233",
        "items" : [ 
            "c", 
            "f"
        ]
      }
   ]
}

从长远来看,它更加灵活,并且还允许您进行索引"像" path"用于查询匹配。

然而,它在这里对你没什么帮助,即使是一致的查询路径,即:

 db.getCollection("coll").find({ "objects.items": Object("c") })

哪个更好,但问题仍然存在,即在同一个单一操作中,来自多个源(无论是对象还是数组)的$pull是不可能的。而且,#34;永远不会增加#34;跨多个文件。

所以,你所能到达的最好的基本上是"尝试" "多重更新"概念,直到选项用尽,没有任何东西可以更新"。随着"修改"结构呈现然后你可以这样做:

var bulk = db.getCollection("coll").initializeOrderedBulkOp(),
    count = 0,
    modified = 1;

while ( modified != 0 ) {
  bulk.find({ "objects.items": "c"}).update({
    "$pull": { "objects.$.items": "c" }
  });
  count++;

  var result = bulk.execute();
  bulk = db.getCollection("coll").initializeOrderedBulkOp();
  modified = result.nModified;
}

print("iterated: " + count);

使用"Bulk" operations API(实际上所有shell方法现在都使用它)基本上得到了更好的写响应"它为您提供有关"更新"尝试。

关键是基本上是"循环"并尝试根据"查询"匹配文档。更新的一部分然后从匹配的数组索引$pull尝试来自"内部数组的项目"符合$pull的条件(作为"查询"本身,仅在数组项目上)。

在每次迭代中,您基本上都会获得" nModified"来自响应的值,当这最终为0时,操作就完成了。

在给定的样本(重组)上,这将进行4次迭代,每次迭代一次"外部"数组成员。更新是"多"正如批量.update()(而不是.updateOne())暗示的那样,因此"最大值"迭代由"最大值"数组元素存在于"外部"整个集合中的数组。所以如果有"一个"记录出来的一千个"如果有20个条目,则迭代将为20,并且只是因为该文档仍然具有可以匹配和修改的内容。

您当前结构下的备用案例并未提及。这很简单,不可能"无:

  1. 单独检索文档

  2. 提取当前密钥

  3. 为该密钥下的数组运行个人$pull

  4. 获取下一份文件,冲洗并重复

  5. 所以"多"是"马上出去"作为一种选择,如果没有一些可能的"预知"可能的"键"在"对象"关键在文件中。

    所以请"改变你的结构"并了解可用的一般限制。

    你不可能在"一个"更新,但至少如果最大的"数组条目"你的文件是" 4"然后最好做"四"更新超过"千"文件比"四千"否则就是必需的。

    另外。请不要"混淆"帖子中的ObjectId值。人们喜欢复制/粘贴"用于测试自己的代码和数据。使用ObjectId("c")这样的有效ObjectId值会明显导致错误,因此对于人们来说不实用。

    做什么"我做了"在列表中,如果你想抽象/混淆,那么用"普通值"正如我所展示的那样。

答案 1 :(得分:1)

您可以采用的一种方法是使用JavaScript本机方法(如 reduce )来创建将在更新中使用的文档。 您基本上需要如下操作:

var itemId = ObjectId("55ba3a983857192828978fec");

db.col.find().forEach(function(doc) {
    var update = {
        "object./.items": itemId, 
        "object./folder1.items": itemId, 
        "object./folder2.items": itemId, 
        "object./testing.items": itemId
    };
    db.col.update(
        { "_id": doc._id },
        {
            "$pull": update
        }
    );    
})

因此,要创建更新对象,需要使用 reduce 方法将数组转换为对象:

var update = Object.getOwnPropertyNames(doc.objects).reduce(function(o, v, i) {
    o["objects." + v + ".items"] = itemId;
    return o;
}, {});

总体而言,您需要使用 Bulk 操作来实现上述更新:

var bulk = db.col.initializeUnorderedBulkOp(),
    itemId = ObjectId("55ba3a983857192828978fec"),
    count = 0;

db.col.find().forEach(function(doc) {
    var update = Object.getOwnPropertyNames(doc.objects).reduce(function(o, v, i) {
        o["objects." + v + ".items"] = itemId;
        return o;
    }, {});
    bulk.find({ "_id": doc._id }).updateOne({
        "$pull": update
    })
    count++;
    if (count % 1000 == 0) {            
        bulk.execute();
        bulk = db.col.initializeUnorderedBulkOp();
    }
})

if (count % 1000 != 0) { bulk.execute(); }
相关问题