コレクションがありますt1
スキーマに次のフィールドがあります
_id, field1, field1
セットしたいfield2
の値field1
のようなsql:
update t1 set field1=field2;
MongoDBでそれを行うにはどうすればよいですか?
ここで良いニュースと悪いニュース。
悪い知らせは、私の知る限り、1回のupdate()呼び出しでは実行できないことです。mongoは、更新中の現在のオブジェクトの参照をサポートしていません。
良いニュースは、それを行うには他の方法があることです。 forEachループを実行できます。
db.item.find(conditions...).forEach( function (doc) {
doc.field1 = doc.field2;
db.item.save(doc);
});
ForEachは、管理シェル( 'mongo'コマンド)で実行するか、特定のドライバーのいくつかのメソッドを使用して実行できます(例:PHP in mongodb.execute( )ここで説明されているとおり: http://www.php.net/manual/en/mongodb.execute.php )
バージョン3.4以降、_$addFields
_集約パイプライン演算子を使用して、クライアント側の処理なしでこれを行うことができます。これが最も効率的な方法です。
_db.collection.aggregate(
[
{ "$addFields": { "field2": "$field1" }},
{ "$out": "collection" }
]
)
_
バージョン3.4より前では、Cursor
オブジェクトを反復処理し、 _$set
_ 演算子を使用して、既存の「field1」値で新しいフィールドを追加する必要があります。効率を最大にするには、「バルク」操作を使用してこれを行う必要があります。
MongoDB 3.2は非推奨 Bulk()
およびその 関連するメソッド したがって、3.2以降では bulkWrite
を使用する必要があります=メソッド。
_var requests = [];
db.collection.find({}, { 'field1': 1 } ).snapshot().forEach(document => {
requests.Push( {
'updateOne': {
'filter': { '_id': document._id },
'update': { '$set': { 'field2': document.field1 } }
}
});
if (requests.length === 1000) {
//Execute per 1000 operations and re-init
db.collection.bulkWrite(requests);
requests = [];
}
});
if(requests.length > 0) {
db.collection.bulkWrite(requests);
}
_
バージョン2.6から3.0までは、Bulk
APIを使用できます。
_var bulk = db.collection.initializeUnorderedBulOp();
var count = 0;
db.collection.find({}, { 'field1': 1 }).snapshot().forEach(function(document) {
bulk.find({ '_id': document._id }).updateOne( {
'$set': { 'field2': document.field1 }
});
count++;
if(count%1000 === 0) {
// Excecute per 1000 operations and re-init
bulk.execute();
bulk = db.collection.initializeUnorderedBulkOp();
}
})
// clean up queues
if(count > 0) {
bulk.execute();
}
_
これは次の方法で実行できます。
db.nameOfCollection.find().forEach(
function (elem) {
db.nameOfCollection.update(
{
_id: elem._id
},
{
$set: {
field2: elem.field1
}
}
);
}
);