有问题的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"
}
]
}
]
}
我主要在做两件事:
搜索特定节点并仅返回结果中的节点。以下是我目前使用的查询(浏览所有相关的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"
}
]
}
]
}
由于上述问题,更新节点文档中的字段也是一个问题。这是我从其他SO问题中得到的查询,但无济于事:
db.getCollection("coll").update({canvases: {$elemMatch:{nodes:{$elemMatch:{_id: ObjectId("54247a68fab6b6775d000060")}}}}}, {$set: {"canvases.$.nodes.$.filePathTemplate": "21"}})
任何帮助都将不胜感激。
答案 0 :(得分:0)
只有$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" ]
}
} ]);
$
不能在嵌套数组中使用; $
时,路径的其余部分必须是“实心”;这意味着如果$
后面有嵌套数组,则必须明确写出其索引以指出要更新的元素。 假设此集合的所有文档级别中的所有_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
});
});