簡體   English   中英

如何使用Mongoid / mongodb批量更新/更新?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM