从MongoDB数组中删除多个文档

5

我的文档包含如下数组:

{
    "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")


2
这不是 MongoDB、JSON 或 BSON 可能存在的有效文档结构。 - Neil Lunn
这种架构中是否可能实现这个功能呢? 如果可以的话,你能提供一些建议吗? - Rishabh Garg
1
这源于基本的JSON表示法。在“解释”之后,不可能没有“键”名称的子文档。如果您想提出问题,那么我们至少要求您提出有效的问题。 - Neil Lunn
抱歉,那是一个错误。我已经进行了更正。 - Rishabh Garg
如果有任何建议,请帮忙。我已经在这个项目上工作了两天了。 - Rishabh Garg
1个回答

0

你的查询只移除第一个匹配项的原因是,在文档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中无法运行,会产生错误。 - Rishabh Garg
c未定义。我该如何从Node.js查询它? - Rishabh Garg
@grishabh,我添加了示例Node.js代码。如果它对你有用,请告诉我。 - Juan Carlos Farah
MongooseJS中的find方法返回一个查询对象(引用)。为了应用每个方法,我们需要数组。 在mongoose中没有toArray方法。 这里是在mongoose中返回数组形式的find查询的参考链接 https://dev59.com/TWEi5IYBdhLWcg3w4Prr - Rishabh Garg
是的,Mongoose 和其他不同,但你可以轻松适应类似于 Model.find({'some.value': 5}, function(err, docs) {//docs已经是一个数组}); 这样的模式。然后只需要把c改成docs,把c.each()改成一个循环遍历docs中的元素即可。这样说清楚了吗?更多信息请看这里 - Juan Carlos Farah
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接