更新Mongodb中深层嵌套文档中的字段

时间:2014-09-26 15:49:59

标签: mongodb

有问题的MongoDB文档结构如下所示:

{
"_id": ObjectId("54247a68fab6b6775d000062"),
"owner": "1",
"version": "Version 1",
"name": "Test20",
"u_at": ISODate("2014-09-25T20:26:16.140Z"),
"c_at": ISODate("2014-09-25T20:26:16.140Z"),
"canvases": [
    {
        "_id": ObjectId("54247a68fab6b6775d000063"),
        "nodes": [
            {
                "_id": ObjectId("54247a68fab6b6775d000060"),
                "filePathTemplate": "LETSDOEMAIL"
            },
            {
                "_id": ObjectId("54247a68fab6b6775d000061"),
                "filePathTemplate": "LETSDOFACEBOOK"
            }
        ]
    }
    ]
}

我主要在做两件事:

  1. 搜索特定节点并仅返回结果中的节点。以下是我目前使用的查询(浏览所有相关的SO问题后):

    db.getCollection("coll").find({_id: ObjectId("54247a68fab6b6775d000062")}, {canvases:{$elemMatch:{nodes:{$elemMatch:{_id: ObjectId("54247a68fab6b6775d000060")}}}}})

    但是这会返回画布,包含搜索到的节点,而不是节点。

    {
    "_id": ObjectId("54247a68fab6b6775d000062"),
    "canvases": [
        {
        "_id": ObjectId("54247a68fab6b6775d000063"),
        "nodes": [
            {
                "_id": ObjectId("54247a68fab6b6775d000060"),
                "filePathTemplate": "LETSDOEMAIL"
            },
            {
                "_id": ObjectId("54247a68fab6b6775d000061"),
                "filePathTemplate": "LETSDOFACEBOOK"
            }
            ]
        }
        ]
    }
    
  2. 由于上述问题,更新节点文档中的字段也是一个问题。这是我从其他SO问题中得到的查询,但无济于事:

    db.getCollection("coll").update({canvases: {$elemMatch:{nodes:{$elemMatch:{_id: ObjectId("54247a68fab6b6775d000060")}}}}}, {$set: {"canvases.$.nodes.$.filePathTemplate": "21"}})

  3. 任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:0)

问题1:

只有$elemMatch的第二个参数中的第一个.find(arg1, arg2)对于定位数组元素才有效,也就是说,只能定位canvases的一个元素,不包括nodes' }。所以.find()在我看来做这种任务是不合适的 但我认为你可以通过以下方法达到目标:

db.coll.aggregate([ {
    $match : {
        _id : ObjectId("54247a68fab6b6775d000062")
    }
}, {
    $redact : {
        $cond : [ {
            $or : [ {
                $gt : [ "$canvases", [] ]
            }, {
                $gt : [ "$nodes", [] ]
            }, {
                $eq : [ "$_id", ObjectId("54247a68fab6b6775d000060") ]
            } ]
        }, "$$DESCEND", "$$PRUNE" ]
    }
} ]);

问题2:

  • 位置运算符$不能在嵌套数组中使用;
  • 因此,当您在数组后使用$时,路径的其余部分必须是“实心”;这意味着如果$后面有嵌套数组,则必须明确写出其索引以指出要更新的元素。

假设此集合的所有文档级别中的所有_id都是唯一的 以下代码供您参考:

var searchKey = ObjectId("54247a68fab6b6775d000060");
var filePathTemplate = "21";

db.getCollection("coll").find({
    canvases : {
        $elemMatch : {
            nodes : {
                $elemMatch : {
                    _id : searchKey
                }
            }
        }
    }
}, {
    "canvases.$" : 1
}).forEach(function(doc) {
    // We need to find out the index of that sub-document which is required to
    // updated in nodes, because nodes is probably very big.
    var i = 0;
    var nodes = doc.canvases[0].nodes; // Only one element in canvases from abover query.
    for (; i < nodes.length && nodes[i]._id.str != searchKey.str; ++i);
    var key = "canvases.$.nodes." + i + ".filePathTemplate"; // Only one "$" can be used.
    var updateNodePart = {};
    updateNodePart[key] = filePathTemplate;

    db.getCollection("coll").update({
        canvases : {
            $elemMatch : {
                nodes : {
                    $elemMatch : {
                        _id : searchKey
                    }
                }
            }
        }
    }, {
        $set : updateNodePart
    });
});