Как @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"
}
}
)
EDIT:
Если вы хотите создать $set
условия на лету то есть что-то, который поможет вам получить индексы для объектов, а затем изменить соответствующим образом, а затем рассмотреть вопрос об использовании MapReduce.
В настоящее время это представляется невозможным с использованием структуры агрегации. Существует неразрешенный открытый JIRA issue, связанный с ним. Однако обходной путь возможен с MapReduce. Основная идея MapReduce заключается в том, что он использует JavaScript в качестве языка запросов, но это, как правило, довольно медленнее, чем структура агрегации, и его нельзя использовать для анализа данных в режиме реального времени.
В вашей операции MapReduce вам необходимо определить пару шагов, т.е. шаг сопоставления (который отображает операцию в каждый документ в коллекции, и операция может либо ничего не делать, либо испускать какой-либо объект с ключами и прогнозируемыми значениями) и сокращение шага (который берет список испущенных значений и сводит его к одному элементу).
Для шага карты вы идеально хотели бы получить для каждого документа в коллекции, индекс для каждого поля массива operations
и еще один ключ, который содержит ключи $set
.
Ваш уменьшить шаг будет функция (которая не делает ничего) просто определяется как 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
);
};
MongoDB не поддерживает соответствие в более чем одним уровнем массив. Рассмотрите возможность изменения модели документа, чтобы каждый документ представлял собой операцию с информацией, общей для набора операций, дублированных в рабочих документах. – wdberkeley