我有以下mongodb文件结构:
[
{
"_id": "04",
"name": "test service 4",
"id": "04",
"version": "0.0.1",
"title": "testing",
"description": "test",
"protocol": "test",
"operations": [
{
"_id": "99",
"oName": "test op 52222222222",
"sid": "04",
"name": "test op 52222222222",
"oid": "99",
"description": "testing",
"returntype": "test",
"parameters": [
{
"oName": "Param1",
"name": "Param1",
"pid": "011",
"type": "582",
"description": "testing",
"value": ""
},
{
"oName": "Param2",
"name": "Param2",
"pid": "012",
"type": "58222",
"description": "testing",
"value": ""
}
]
}
]
}
]
我已经能够使用$
elemMatch来更新操作中的字段,但是当我尝试对参数执行相同的操作(修改)时,它似乎不起作用。我想知道我应该尝试哪种其他方法,以便能够成功更新特定参数中的字段(通过其pid查找)。
我当前拥有但不起作用的更新代码如下所示:
var oid = req.params.operations;
var pid = req.params.parameters;
collection.update({"parameters":{"$elemMatch": {"pid": pid}}},{"$set": {"parameters.$.name":req.body.name, "parameters.$.description": req.body.description,"parameters.$.oName": req.body.oName,"parameters.$.type": req.body.type} }, function(err, result) {
if (err) {
console.log('Error updating service: ' + err);
res.send({'error':'An error has occurred'});
} else {
// console.log('' + result + ' document(s) updated');
res.send(result);
}
});
MongoDB3.6及更高版本提供了一项新功能,该功能允许您使用位置过滤的$\[<identifier>\]
语法来更新嵌套数组,以匹配特定元素并arrayFilters
在update语句中应用不同的条件:
const { oid, pid } = req.params;
const { name, oName, description, type } = req.body;
collection.update(
{
"_id": 1,
"operations": {
"$elemMatch": {
oid, "parameters.pid": pid
}
}
},
{ "$set": {
"operations.$[outer].parameters.$[inner].name": name,
"operations.$[outer].parameters.$[inner].description": description,
"operations.$[outer].parameters.$[inner].oName": oName,
"operations.$[outer].parameters.$[inner].type": type
} },
{ "arrayFilters": [
{ "outer.oid": oid },
{ "inner.pid": pid }
] }, (err, result) => {
if (err) {
console.log('Error updating service: ' + err);
res.send({'error':'An error has occurred'});
} else {
// console.log('' + result + ' document(s) updated');
res.send(result);
}
});
正如@wdberkeley在他的评论中提到的:
MongoDB不支持匹配多个级别的数组。考虑更改文档模型,以便每个文档都代表一个操作,并具有操作文档中重复的一组操作所共有的信息。
我同意上述观点,并建议重新设计架构,因为MongoDB引擎不支持多个位置运算符
但是,如果您知道具有要预先更新的参数对象的操作数组的索引,则更新查询将为:
db.collection.update(
{
"_id" : "04",
"operations.parameters.pid": "011"
},
{
"$set": {
"operations.0.parameters.$.name": "foo",
"operations.0.parameters.$.description": "bar",
"operations.0.parameters.$.type": "foo"
}
}
)
编辑:
如果您想 $set
即时创建条件,即可以帮助您获取对象索引然后进行相应修改的条件,请考虑使用
MapReduce 。
当前,使用聚合框架似乎不可能做到这一点。与之相关的一个未解决的未解决
JIRA问题 。但是,可以使用
MapReduce
解决。MapReduce的基本思想是它使用JavaScript作为查询语言,但是它比聚合框架要慢得多,因此不应用于实时数据分析。
在您的MapReduce操作中,您需要定义几个步骤,即映射步骤(将操作映射到集合中的每个文档中,并且该操作不能执行任何操作或使用键和投影值发出某些对象)和减少步骤(它接受发射值列表并将其简化为单个元素)。
对于映射步骤,理想情况下,您希望获取集合中的每个文档,每个operations
数组字段的索引以及包含这些$set
键的另一个键。
您的reduce步骤将是一个简单地定义为的函数(不执行任何操作) var reduce = function() {};
然后,MapReduce操作的最后一步将创建一个单独的集合操作,其中包含发出的操作数组对象以及带有$set
条件的字段。在原始集合上运行MapReduce操作时,可以定期更新此集合。总而言之,此MapReduce方法如下所示:
var map = function(){
for(var i = 0; i < this.operations.length; i++){
emit(
{
"_id": this._id,
"index": i
},
{
"index": i,
"operations": this.operations[i],
"update": {
"name": "operations." + i.toString() + ".parameters.$.name",
"description": "operations." + i.toString() + ".parameters.$.description",
"type": "operations." + i.toString() + ".parameters.$.type"
}
}
);
}
};
var reduce = function(){};
db.collection.mapReduce(
map,
reduce,
{
"out": {
"replace": "operations"
}
}
);
operations
从MapReduce操作查询输出集合通常会给您结果:
db.operations.findOne()
输出 :
{
"_id" : {
"_id" : "03",
"index" : 0
},
"value" : {
"index" : 0,
"operations" : {
"_id" : "96",
"oName" : "test op 52222222222",
"sid" : "04",
"name" : "test op 52222222222",
"oid" : "99",
"description" : "testing",
"returntype" : "test",
"parameters" : [
{
"oName" : "Param1",
"name" : "foo",
"pid" : "011",
"type" : "foo",
"description" : "bar",
"value" : ""
},
{
"oName" : "Param2",
"name" : "Param2",
"pid" : "012",
"type" : "58222",
"description" : "testing",
"value" : ""
}
]
},
"update" : {
"name" : "operations.0.parameters.$.name",
"description" : "operations.0.parameters.$.description",
"type" : "operations.0.parameters.$.type"
}
}
}
然后,您可以使用db.operations.find()
方法中的游标进行迭代,并相应地更新您的集合:
var oid = req.params.operations;
var pid = req.params.parameters;
var cur = db.operations.find({"_id._id": oid, "value.operations.parameters.pid": pid });
// Iterate through results and update using the update query object set dynamically by using the array-index syntax.
while (cur.hasNext()) {
var doc = cur.next();
var update = { "$set": {} };
// set the update query object
update["$set"][doc.value.update.name] = req.body.name;
update["$set"][doc.value.update.description] = req.body.description;
update["$set"][doc.value.update.type] = req.body.type;
db.collection.update(
{
"_id" : oid,
"operations.parameters.pid": pid
},
update
);
};
我正在尝试更新嵌套数组中的值,但无法使其工作。 我的对象是这样的 提前谢谢!
我正在使用平均堆栈在网格中显示以下数组。 嵌套数组:
问题内容: 我正在尝试更新嵌套数组中的值,但无法使其正常工作。 我的对象是这样的 我需要将值推送到“ answeredBy”数组。 在下面的示例中,我尝试将“成功”字符串推到“ 123 _id”对象的“ answeredBy”数组中,但是它不起作用。 我找到了此链接,但其答案仅表示我应该使用类似结构的对象而不是数组。这不适用于我的情况。我真的需要将我的对象嵌套在数组中 如果您能在这里帮助我,那就太
我需要更新嵌套在我的用户文档中的一个字段,该字段包含一个part对象数组,以添加新的part。一个part对象如下所示: 所以这意味着$addToset对我的情况没有好处...现在我不知道该怎么办。
我有以下JSON: 我希望能够将内容推送到与迭代 2 关联的任务数组中。如何正确查询并插入到正确的位置?这就是我到目前为止所拥有的,但它总是插入到与迭代 1 关联的任务数组中。 我已经看到了这个:MongoDB嵌套数组查询,但他只是试图推送到一个嵌套数组。
我有以下mongodb文档结构: 我已经能够使用$elemMatch来更新操作中的字段,但当我尝试对参数执行相同的操作(修改)时,它似乎不起作用。我想知道,为了能够通过pid查找特定参数中的字段,我应该尝试其他什么方法来成功更新字段。 我目前拥有但不起作用的更新代码如下所示: