这个问题已经在这里有一个答案:
我有以下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);
}
});
随着MongoDB的3.6及以上提供了一个新功能,可以让你通过,以便通过在更新语句the positional filtered $\[<identifier>\]
以匹配特定的元素,并应用不同的条件下使用arrayFilters
语法来更新嵌套的数组:
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的引擎不支持多个位置操作符(见Multiple use of the positional $
operator to update nested arrays)
但是,如果你知道操作阵列具有参数对象必须事先更新,则更新查询将是指数:
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 issue。然而,一个解决办法是可能的MapReduce。与MapReduce的基本思想是,它使用JavaScript作为其查询语言,但是这往往比聚合框架相当慢,不应被用于实时数据分析。
在你的精简操作,你需要定义几个步骤,即映射步骤(其中操作映射到集合中的所有文档,而操作可以什么都不做或发出与键和预测值的一些对象)和还原步骤(这需要发射的值的列表和它减少到一个单一的元素)。
对于地图的步骤,你最好希望集合中获得的每一个文件,该指数为每个operations
阵列场和包含$set
键的另一个关键。
你减少的步骤将是一个函数(什么都不做)简单地定义为var reduce = function() {};
然后在精简操作的最后一步将创建一个包含发射操作数组对象与该$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"
}
}
);
查询从MapReduce的操作输出收集operations
通常会给你的结果:
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
);
};
如果是经常变化的数据,你应该扁平化的结构和分离,从一个不起变化很大的数据。
如果是不经常更改的数据,整个数据对象不是大规模的,只是修改对象的客户端,并更新整个对象。
我们将设法找到外阵列(i)和内部阵列(J)的索引,然后更新
collection.findById(04)
.then(result =>{
for(let i = 0; i<result.operations.length; i++){
if(result.operation[i]._id == "99"){
let parameters = result.operations[i].parameters;`enter code here`
for(let j = 0; j<parameters.length; j++){
if(parameters[j].pid == "011"){
console.log("i", i);
console.log("j", j);
let data = {}
data["operations." + i + ".parameters." + j + ".oName"] = updateoName
data["operations." + i + ".parameters." + j + ".name"] = updatename
data["operations." + i + ".parameters." + j + ".pid"] = updatepid
data["operations." + i + ".parameters." + j + ".description"] = updatedescription
data["operations." + i + ".parameters." + j + ".value"] = updatevalue
console.log(data)
collection.update({
"_id": "04"
},{
$set: data
})
.then(dbModel => res.json(dbModel))
}
}
}
}
})
与蒙戈版本3.6开始,你可以使用$ []在$ []更新嵌套数组连词
更新嵌套的数组与$连词[]
的$ []过滤位置操作,在与所有$ []位置操作者结合可以被用于更新嵌套阵列。