特定のドキュメントの文字列を置き換える必要があります。私はこのコードをグーグルで検索しましたが、残念ながら何も変更しません。以下の行の構文についてはわかりません。
pulpdb = db.getSisterDB("pulp_database");
var cursor = pulpdb.repos.find();
while (cursor.hasNext()) {
var x = cursor.next();
x['source']['url'].replace('aaa', 'bbb'); // is this correct?
db.foo.update({_id : x._id}, x);
}
値を確認するためにデバッグ出力を追加したいのですが、MongoDBシェルを使用した経験がありません。これを置き換えるだけです:
{ "source": { "url": "http://aaa/xxx/yyy" } }
と
{ "source": { "url": "http://bbb/xxx/yyy" } }
一般的には修正されません。文字列http://aaa/xxx/aaa
(yyy
はaaa
と等しい)がある場合、http://bbb/xxx/bbb
になります。しかし、これで問題がなければ、コードは機能します。
デバッグ情報を追加するには、print
関数を使用します。
var cursor = db.test.find();
while (cursor.hasNext()) {
var x = cursor.next();
print("Before: "+x['source']['url']);
x['source']['url'] = x['source']['url'].replace('aaa', 'bbb');
print("After: "+x['source']['url']);
db.test.update({_id : x._id}, x);
}
(ちなみに、オブジェクトを印刷したい場合は、printjson
関数もあります)
MongoDB 2.6以降を使用している場合にこれを行う最良の方法は、 _.forEach
_ メソッドを使用してカーソルオブジェクトをループし、各ドキュメントを使用して各ドキュメントを更新する "bulk" です。最大効率のための操作。
_var bulk = db.collection.initializeOrderedBulkOp();
var count = 0;
db.collection.find().forEach(function(doc) {
print("Before: "+doc.source.url);
bulk.find({ '_id': doc._id }).update({
'$set': { 'source.url': doc.source.url.replace('aaa', 'bbb') }
})
count++;
if(count % 200 === 0) {
bulk.execute();
bulk = db.collection.initializeOrderedBulkOp();
}
// Clean up queues
if (count > 0)
bulk.execute();
_
MongoDB 3.2 から Bulk() APIとそれに関連する methods は非推奨です db.collection.bulkWrite()
メソッド。
カーソルをループしてクエリを動的に作成し、配列に対する各操作を _$Push
_ する必要があります。
_var operations = [];
db.collection.find().forEach(function(doc) {
print("Before: "+doc.source.url);
var operation = {
updateOne: {
filter: { '_id': doc._id },
update: {
'$set': { 'source.url': doc.source.url.replace('aaa', 'bbb') }
}
}
};
operations.Push(operation);
})
operations.Push({
ordered: true,
writeConcern: { w: "majority", wtimeout: 5000 }
})
db.collection.bulkWrite(operations);
_
MongoDBは、mapreduceを介して文字列の検索/置換を行うことができます。はい、そのための非常に特殊なデータ構造が必要です。トップキーには何も含めることはできませんが、value
の下のサブドキュメントの下にすべてを保存する必要があります。このような:
{
"_id" : ObjectId("549dafb0a0d0ca4ed723e37f"),
"value" : {
"title" : "Top 'access denied' errors",
"parent" : "system.admin_reports",
"p" : "\u0001\u001a%"
}
}
これをきちんとセットアップしたら、次のことができます。
$map = new \MongoCode("function () {
this.value['p'] = this.value['p'].replace('$from', '$to');
emit(this._id, this.value);
}");
$collection = $this->mongoCollection();
// This won't be called.
$reduce = new \MongoCode("function () { }");
$collection_name = $collection->getName();
$collection->db->command([
'mapreduce' => $collection_name,
'map' => $map,
'reduce' => $reduce,
'out' => ['merge' => $collection_name],
'query' => $query,
'sort' => ['_id' => 1],
]);
今日、
Mongo 4.2
、 db.collection.updateMany
(db.collection.update
のエイリアス)は集計パイプラインを受け入れることができ、最終的に独自の値に基づいてフィールドの更新を許可します。Mongo 4.4
の開始 $replaceOne
を使用すると、文字列の一部を非常に簡単に置き換えることができます。// { "source" : { "url" : "http://aaa/xxx/yyy" } }
// { "source" : { "url" : "http://eee/xxx/yyy" } }
db.collection.updateMany(
{ "source.url": { $regex: /aaa/ } },
[{
$set: { "source.url": {
$replaceOne: { input: "$source.url", find: "aaa", replacement: "bbb" }
}}
}]
)
// { "source" : { "url" : "http://bbb/xxx/yyy" } }
// { "source" : { "url" : "http://eee/xxx/yyy" } }
{ "source.url": { $regex: /aaa/ } }
)は一致クエリで、更新するドキュメント("aaa"
を含むドキュメント)をフィルタリングします$set: { "source.url": {...
)は、更新集約パイプラインです(角括弧が集約パイプラインの使用を示すことに注意してください):$set
は、この場合はフィールドの値を置き換える新しい集計演算子(Mongo 4.2
)です。$replaceOne
演算子を使用して計算されます。 source.url
が独自の値($source.url
)に基づいて直接変更される方法に注意してください。これはサーバー側で完全に処理されるため、質問のデバッグ印刷部分を実行できないことに注意してください。