从MongoDB中的数组中删除多个文档

Posted

技术标签:

【中文标题】从MongoDB中的数组中删除多个文档【英文标题】:Remove multiple documents from array in MongoDB 【发布时间】:2015-05-01 05:14:04 【问题描述】:

我的文档包含如下数组:


    "differentialDiagnosis" : "IART/Flutter",
    "explanation" : "The rhythm.",
    "fileName" : "A115a JPEG.jpg",
    "history" : "1 year old with fussiness",
    "interpretationList" : [ 
        
           "interpretations" : [
                ObjectId("54efe7c8d6d5ca3d5c580a22"), 
                ObjectId("54efe80bd6d5ca3d5c580a26")
            ]
        , 
        
            "interpretations" : [ 
                ObjectId("54efe80bd6d5ca3d5c580a26"), 
                ObjectId("54efe82ad6d5ca3d5c580a28")
             ]
        
    ],

我想删除所有出现的ObjectId("54efe80bd6d5ca3d5c580a26"), 但我写了一个查询:

db.ekgs.update('interpretationList.interpretations':ObjectId("54c09fb3581c4c8c218d1a40"), $pull: 'interpretationList.$.interpretations': ObjectId("54c09fb3581c4c8c218d1a40"))

仅删除ObjectId("54efe80bd6d5ca3d5c580a26") 的第一次出现

【问题讨论】:

这不是 MongoDB 或 JSON 或 BSON 下可能存在的有效文档结构。 这种模式可以实现吗?如果是,你能建议吗? 这源于基本的 JSON 表示法。 “解释”之后不可能是没有“关键”名称的子文档。如果你想问一个问题,那么我们至少要求你问一些有效的东西。 抱歉打错了,我更正了。 如果任何人有任何建议,请提供帮助。我从过去 2 天开始就在处理这个问题。 【参考方案1】:

您的查询仅删除第一个匹配项的原因是,正如文档中this page 中所述,“位置$ 运算符充当与查询文档匹配的第一个元素的占位符”。

问题在于,使用在嵌入式数组中的嵌入式对象中具有嵌入式数组的架构来处理这些类型的更新确实很棘手。为了解决这个问题,如果您能够扁平化架构,那么您的更新会变得更加容易。因此,如果相反,您的文档看起来像这样:


    "differentialDiagnosis" : "IART/Flutter",
    "explanation" : "The rhythm.",
    "fileName" : "A115a JPEG.jpg",
    "history" : "1 year old with fussiness",
    "interpretations" : [
        ObjectId("54efe7c8d6d5ca3d5c580a22"), 
        ObjectId("54efe80bd6d5ca3d5c580a26"),
        ObjectId("54efe82ad6d5ca3d5c580a28")
    ]

那么您的查询将与以下查询一样简单。 (如果您想更新多个文档,请记住添加 "multi": true 作为选项)。

db.ekgs.update(
     "interpretations": ObjectId("54efe80bd6d5ca3d5c580a26"),
     "$pull":  "interpretations": ObjectId("54efe80bd6d5ca3d5c580a26") 
);

但我了解您可能无法更改架构。在这种情况下,您可以尝试需要一个小脚本的解决方案。在mongo shell 中,你可以使用下面这段 javascript 来进行操作。

// Get cursor with documents requiring updating.
var oid = ObjectId("54efe80bd6d5ca3d5c580a26");
var c = db.ekgs.find( "interpretationList.interpretations": oid );

// Iterate through cursor, removing oid from each subdocument in interpretationList.
while (c.hasNext()) 
    var isModified = false;
    var doc = c.next(); 
    var il = doc.interpretationList;
    for (var i in il) 
        var j = il[i].interpretations.length;
        while (j--) 

            // If oid to remove is present, remove it from array
            // and set flag that the document has been modified.
            if (il[i].interpretations[j].str === oid.str) 
                il[i].interpretations.splice(j, 1);
                isModified = true;
            
        
    

    // If modified, update interpretationList for document.
    if (isModified) 
        db.ekgs.update( "_id": doc._id ,  "$set":  "interpretationList": il );
    

更新:使用 Node.js 驱动程序如何工作的示例。

// Get cursor with documents requiring updating.
var oid = new ObjectID("54efe80bd6d5ca3d5c580a26");
var ekgs = db.collection("ekgs");
ekgs.find( "interpretationList.interpretations": oid ,
          function(err, c)     

    if(err) throw err;

    // Iterate through cursor, removing oid from each subdocument in interpretationList.
    c.each(function(err, doc) 
        if (err) throw err;

        // If doc is null then the cursor is exhausted/empty and closed.
        if (doc != null) 
            var isModified = false;         
            var il = doc.interpretationList;
            for (var i in il) 
                var j = il[i].interpretations.length;
                while (j--) 

                    // If oid to remove is present, remove it from array
                    // and set flag that the document has been modified.
                    if (il[i].interpretations[j].equals(oid))                          
                        il[i].interpretations.splice(j, 1);
                        isModified = true;
                    
                
                       

            // If modified, update interpretationList for document.
            if (isModified) 
                ekgs.update( "_id": doc._id ,
                             "$set":  "interpretationList": il ,
                            function(err, res) 

                    if (err) throw err;

                    // Callback.
                    console.log(res);
                );
            
        
    );
);

【讨论】:

这样好吗?我认为这会影响我们的服务响应时间。它在 mongo shell.it 中不起作用。 c 未定义。我如何从 nodeJs 中查询它。 我明白了。问题是,在mongo shell 中,您可以将db.collection.find() 的返回值分配给一个变量。因此这一行:var c = db.ekgs.find( "interpretationList.interpretations": oid ); 在 Node.js 中,您需要将此作为回调,让我将其添加到我的答案中。 @grishabh,我添加了示例 Node.js 代码。让我知道它是否适合您。 您使用的是 MongoDB 原生 Node.js 驱动程序吗?

以上是关于从MongoDB中的数组中删除多个文档的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB:使用pymongo在一个集合中删除多个文档中的数组值

如何从 MongoDB 文档中的双重嵌套数组中删除元素。

使用 MongoDB 从数组中删除特定项目

获取数组中每个索引的子文档元素计数并更新子文档键 - 数组中的子文档(IN MONGODB)

从 Mongo DB 文档的数组中的对象数组中删除一个值

如何从 Mongo DB 中的子文档数组中删除匹配条件的子文档