Cara terbaik untuk melakukan ini adalah dalam versi 4.2+ yang memungkinkan penggunaan pipa agregasi dalam dokumen pembaruan dan updateOne
, updateMany
atau update
metode pengumpulan. Perhatikan bahwa yang terakhir telah usang di sebagian besar jika tidak semua driver bahasa.
MongoDB 4.2+
Versi 4.2 juga memperkenalkan $set
operator tahap pipa yang merupakan alias untuk $addFields
. Saya akan gunakan di $set
sini karena memetakan dengan apa yang kita coba capai.
db.collection.<update method>(
{},
[
{"$set": {"name": { "$concat": ["$firstName", " ", "$lastName"]}}}
]
)
MongoDB 3.4+
Dalam 3.4+ Anda dapat menggunakan $addFields
dan $out
operator pipa agregasi.
db.collection.aggregate(
[
{ "$addFields": {
"name": { "$concat": [ "$firstName", " ", "$lastName" ] }
}},
{ "$out": "collection" }
]
)
Perhatikan bahwa ini tidak memperbarui koleksi Anda tetapi ganti koleksi yang ada atau buat yang baru. Juga untuk memperbarui operasi yang memerlukan "ketik casting" Anda akan memerlukan pemrosesan sisi klien, dan tergantung pada operasi, Anda mungkin perlu menggunakan find()
metode ini daripada.aggreate()
metode.
MongoDB 3.2 dan 3.0
Cara kami melakukan ini adalah dengan $project
memasukkan dokumen kami dan menggunakan $concat
operator agregasi string untuk mengembalikan string yang digabungkan. we Dari sana, Anda lalu iterasi kursor dan gunakan $set
operator pembaruan untuk menambahkan bidang baru ke dokumen Anda menggunakan operasi massal untuk efisiensi maksimum.
Permintaan agregasi:
var cursor = db.collection.aggregate([
{ "$project": {
"name": { "$concat": [ "$firstName", " ", "$lastName" ] }
}}
])
MongoDB 3.2 atau lebih baru
dari ini, Anda perlu menggunakan bulkWrite
metode ini.
var requests = [];
cursor.forEach(document => {
requests.push( {
'updateOne': {
'filter': { '_id': document._id },
'update': { '$set': { 'name': document.name } }
}
});
if (requests.length === 500) {
//Execute per 500 operations and re-init
db.collection.bulkWrite(requests);
requests = [];
}
});
if(requests.length > 0) {
db.collection.bulkWrite(requests);
}
MongoDB 2.6 dan 3.0
Dari versi ini Anda perlu menggunakan Bulk
API yang sekarang sudah tidak digunakan lagi dan metode terkaitnya .
var bulk = db.collection.initializeUnorderedBulkOp();
var count = 0;
cursor.snapshot().forEach(function(document) {
bulk.find({ '_id': document._id }).updateOne( {
'$set': { 'name': document.name }
});
count++;
if(count%500 === 0) {
// Excecute per 500 operations and re-init
bulk.execute();
bulk = db.collection.initializeUnorderedBulkOp();
}
})
// clean up queues
if(count > 0) {
bulk.execute();
}
MongoDB 2.4
cursor["result"].forEach(function(document) {
db.collection.update(
{ "_id": document._id },
{ "$set": { "name": document.name } }
);
})
Anda harus mengulanginya. Untuk kasus spesifik Anda:
sumber
save()
sepenuhnya menggantikan dokumen. Sebaiknya gunakanupdate()
saja.db.person.update( { _id: elem._id }, { $set: { name: elem.firstname + ' ' + elem.lastname } } );
create_guid
yang hanya menghasilkan panduan unik per dokumen ketika iterasi denganforEach
cara ini (yaitu hanya menggunakancreate_guid
dalamupdate
pernyataan yangmutli=true
menyebabkan panduan yang sama dihasilkan untuk semua dokumen). Jawaban ini sangat cocok untuk saya. +1Rupanya ada cara untuk melakukan ini secara efisien sejak MongoDB 3.4, lihat jawaban styvane .
Jawaban usang di bawah
Anda tidak dapat merujuk ke dokumen itu sendiri dalam pembaruan (belum). Anda harus mengulang melalui dokumen dan memperbarui setiap dokumen menggunakan fungsi. Lihat jawaban ini sebagai contoh, atau ini untuk sisi server
eval()
.sumber
update
operasi. Permintaan fitur terkait ini juga masih belum terselesaikan.OPEN
.Untuk database dengan aktivitas tinggi, Anda dapat mengalami masalah di mana pembaruan Anda memengaruhi perubahan catatan yang aktif dan untuk alasan ini saya sarankan menggunakan snapshot ()
http://docs.mongodb.org/manual/reference/method/cursor.snapshot/
sumber
snapshot()
:Deprecated in the mongo Shell since v3.2. Starting in v3.2, the $snapshot operator is deprecated in the mongo shell. In the mongo shell, use cursor.snapshot() instead.
tautanMengenai jawaban ini , fungsi foto tidak digunakan lagi dalam versi 3.6, sesuai dengan pembaruan ini . Jadi, pada versi 3.6 dan di atasnya, dimungkinkan untuk melakukan operasi dengan cara ini:
sumber
Mulai
Mongo 4.2
,db.collection.update()
dapat menerima pipa agregasi, akhirnya memungkinkan pembaruan / pembuatan bidang berdasarkan bidang lain:Bagian pertama
{}
adalah kueri kecocokan, memfilter dokumen mana yang akan diperbarui (dalam kasus kami semua dokumen).Bagian kedua
[{ $set: { name: { ... } }]
adalah pipa agregasi pembaruan (perhatikan tanda kurung kotak menandakan penggunaan pipa agregasi).$set
adalah operator agregasi baru dan alias$addFields
.Jangan lupa
{ multi: true }
, jika tidak , hanya dokumen yang cocok pertama yang akan diperbarui.sumber
Saya mencoba solusi di atas tetapi saya merasa tidak cocok untuk sejumlah besar data. Saya kemudian menemukan fitur aliran:
sumber
Inilah yang kami buat untuk menyalin satu bidang ke bidang lain untuk ~ 150_000 catatan. Butuh sekitar 6 menit, tetapi masih jauh lebih sedikit sumber daya intensif daripada instantiate dan iterate atas jumlah objek ruby yang sama.
sumber
Dengan MongoDB versi 4.2+ , pembaruan lebih fleksibel karena memungkinkan penggunaan pipa agregasi di dalamnya
update
,updateOne
danupdateMany
. Anda sekarang dapat mengubah dokumen Anda menggunakan operator agregasi kemudian memperbarui tanpa perlu menjelaskan status$set
perintah (sebagai gantinya kami menggunakan$replaceRoot: {newRoot: "$$ROOT"}
)Di sini kami menggunakan kueri agregat untuk mengekstrak timestamp dari bidang ObjectID "_id" MongoDB dan memperbarui dokumen (Saya bukan ahli dalam SQL tapi saya pikir SQL tidak menyediakan ObjectID yang dibuat secara otomatis yang memiliki timestamp untuk itu, Anda harus secara otomatis membuat tanggal itu)
sumber
{ $replaceRoot: { newRoot: "$$ROOT" } }
; itu berarti mengganti dokumen dengan sendirinya, yang tidak ada gunanya. Jika Anda mengganti$addFields
dengan alias-nya$set
danupdateMany
yang merupakan salah satu alias untukupdate
, maka Anda mendapatkan jawaban yang sama persis seperti yang satu ini di atas.