MongoDB3.6以降
MongoDB 3.6以降には、位置フィルター処理された$\[<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);
}
});
MongoDB 3.4以前の場合:
@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
を含む別のキー キー。
削減ステップは、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
);
};