如何使用mongoid / mongodb批量更新/ upsert?

时间:2014-11-23 19:58:57

标签: ruby-on-rails ruby mongodb mongoid

我有一个包含数百万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"}
                        ])

Fyi,可能会有类似的问题/答案in this SO post,但老实说,我不会听从答案。

4 个答案:

答案 0 :(得分:2)

引用问题中的最佳答案可以简化为

try 
{
    // ...
    var claimsIdentity = (ClaimsIdentity)this.RequestContext.Principal.Identity;
    foreach(var claim in claimsIdentity.Claims)
    {
        // claim.value;
        // claim.Type
    }
    // ...
}

答案 1 :(得分:1)

首先,您需要仅对Orders的匹配ID进行过滤orders_to_update。 您可以使用any_in Criteria method过滤它们。然后使用update_all批量更新所有这些内容。

像这样:

orders_to_update = [BSON::ObjectId('5471944843687229cdfb0000'), BSON::ObjectId('5471944843687229cdfc0000')]

Order.any_in(id: orders_to_update).update_all(status: "closed")

答案 2 :(得分:1)

这里真正的问题是更新。更新很慢,因为它需要读取,替换和更改文档。

我已经被同一个问题阻挡了很多天。我在stackoverflow或其他任何网站上都找不到任何解决方案。因此,我写了自己的解决方案。也许你会发现它不是很干净"但是它可以用很好的时间结果。

解决方案包括再次销毁这个文件。 Destroy非常快,并使用批量执行创建新文档" 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

答案 3 :(得分:-1)

对于更新或替换操作,将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()查询条件匹配,则更新操作仅插入单个文档。 希望这会有所帮助。