[英]How to bulk update/upsert with mongoid/mongodb?
我有一個包含數百萬個Order
文檔的數據庫。 我使用以下方法批量插入它們:
Order.collection.insert([
{:_id=>BSON::ObjectId('5471944843687229cdfb0000'), :status=>"open", :name=> "Benny"},
{:_id=>BSON::ObjectId('5471944843687229cdfc0000'), :status=>"open", :name=> "Allan"}
])
我經常需要更新訂單上的status
屬性。 用update_attribute
方法單獨更新它們可能會效率低下。
如何批量更新多個MongoDB文檔?
所需的解決方案最好用下面的“虛構”代碼來描述:
# IMPORTANT: The exemplified upsert method does not exist
Order.collection.upsert([
{:_id=>BSON::ObjectId('5471944843687229cdfb0000'), :status=>"closed"},
{:_id=>BSON::ObjectId('5471944843687229cdfc0000'), :status=>"some_other_status"}
])
僅供參考, 在這篇SO帖子中可能會有類似的問題/答案,但是老實說,我不遵循答案。
所引用問題的最佳答案可以簡化為
id_status = [['5471944843687229cdfb0000','closed'], ...]
bulk_order = id_status.map do |id, status| # Using array destructuration
{ update_one:
{
filter: { _id: id },
update: { :'$set' => {
status: status,
}}
}
}
end
YourCollection.collection.bulk_write(bulk_order)
首先,您只需要為orders_to_update
那些匹配ID過濾Orders
。 您可以使用any_in Criteria方法過濾它們。 然后使用update_all批量更新所有它們。
像這樣:
orders_to_update = [BSON::ObjectId('5471944843687229cdfb0000'), BSON::ObjectId('5471944843687229cdfc0000')]
Order.any_in(id: orders_to_update).update_all(status: "closed")
真正的問題是更新 。 更新很慢,因為它需要讀取,替換和更改文檔。
我被同一問題困擾了很多天了。 我沒有在stackoverflow或任何其他網站中找到任何解決方案。 因此,我編寫了自己的解決方案。 也許您會發現它不是很“干凈”,但是可以在出色的時間效果下工作。
解決方法是重新銷毀創建該文件 。 銷毀非常快,並且使用批量執行“ collection.insert”創建新文檔非常快。
def get_orders(*params)
Order.where(# some conditions).asc(:id)
end
namespace :my_collection_repairer do
desc ""
task update: :environment do
all_orders = get_orders(# some conditions)
while all_orders.count > 0
num_docs = all_orders.count
group_size = 10000
num_groups = (Float(num_docs) / group_size).ceil
puts "#{num_docs} documents found. #{num_groups} groups calculated."
1.upto(num_groups) do |group|
updated_order_list = []
order_group = all_orders.page(group).per(group_size)
puts "group #{group}"
order_group.each do |order|
updated_order = update_order(order) # this represents your custom update method
updated_order_list << updated_order.as_document
order.destroy
end
Order.collection.insert(updated_order_list)
puts "Group #{group} updated."
end
all_orders = get_orders(# some conditions)
end
end
end
將upsert選項設置為true以進行更新或替換操作,並具有以下語法 :
bulk.find( { status: "closed" } ).update( { $set: { status: "some_other_status" } } );
bulk.execute();
將多次更新操作添加到批量操作列表中。 該方法更新現有文檔中的特定字段。
使用Bulk.find()方法來指定確定要更新哪些文檔的條件。 Bulk.find.update()方法更新所有匹配的文檔。 要指定單個文檔更新,請參見Bulk.find.updateOne() 。
var bulk = db.collection.initializeUnorderedBulkOp();
bulk.find( { status: "closed" } ).upsert().update(
{
$set: { status: "some_other_status"}
}
);
bulk.execute();
注意事項 :
要指定upsert:對於此操作為true,請使用Bulk.find.upsert() 。 使用Bulk.find.upsert() ,如果沒有文檔與Bulk.find()查詢條件匹配,則更新操作僅插入單個文檔。 希望這可以幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.