簡體   English   中英

如何確定實際插入了多少個Mongo文檔?

[英]How do I find out how many Mongo documents were actually inserted?

我有一個看起來像這樣的函數:

def insert_multiple_cakes(cake_list)
  ensure_indexes

  insert_list = cake_list.map { |cake| mongofy_values(cake.to_hash) }

  inserted = db[CAKE_COLLECTION].insert(insert_list, w: 0)

  return inserted.length
end

該函數的目標是將cake_list所有蛋糕插入Mongo數據庫。 數據庫中已經存在的任何蛋糕都應忽略。 該函數應返回插入的蛋糕數,因此,如果cake_list包含5個蛋糕,並且數據庫中已經存在其中2個蛋糕,則該函數應返回3。

我的問題是經過一個小時的實驗,我得出以下結論:

  • 如果寫問題( :w選項)為0,則insert調用將靜默忽略所有重復的插入,並且返回值包含所有輸入文檔,即使是未插入的文檔。 設置:continue_on_error:collect_on_error ,返回值始終包含所有文檔,並且收集到的錯誤列表始終為空。

  • 如果寫關注為1,則如果輸入文檔之間有任何重復項,則插入調用將失敗,並顯示Mongo::OperationFailure 設置:continue_on_error:collect_on_error ,當有重復項時插入總是失敗。

因此,在我看來,實現此目標的唯一方法是遍歷輸入列表,搜索每個文檔並過濾掉已經存在的文檔。 我的應用程序一次將要處理(至少)數千個插入,所以我喜歡這個計划,就像我想跨過橋一樣。

我是否誤解了某些東西,還是Ruby客戶端可能被竊聽了?


為了說明這一點,此功能完全可以滿足我的要求並可以正常工作:

def insert_multiple_cakes(cake_list)
  ensure_indexes

  collection = db[CAKE_COLLECTION]

  # Filters away any cakes that already exists in the database.
  filtered_list = cake_list.reject { |cake|
    collection.count(query: {"name" => cake.name}) == 1
  }

  insert_list = filtered_list.map { |cake| mongofy_values(cake.to_hash) }

  inserted = collection.insert(insert_list)

  return inserted.length
end

問題在於它執行的搜索量不勝枚舉,實際上只需要插入一個即可。


Mongo::Collection#insert文檔

您可以執行以下操作( source ):

coll = MongoClient.new().db('test').collection('cakes')
  bulk = coll.initialize_unordered_bulk_op
  bulk.insert({'_id' => "strawberry"})
  bulk.insert({'_id' => "strawberry"}) # duplicate key
  bulk.insert({'_id' => "chocolate"})
  bulk.insert({'_id' => "chocolate"}) # duplicate key
begin
  bulk.execute({:w => 1}) # this is the default but don't change it to 0 or you won't get the errors
rescue => ex
  p ex
  p ex.result
end

ex.result包含ninserted以及每個失敗的原因。

{"ok"=>1,
 "n"=>2,
 "code"=>65,
 "errmsg"=>"batch item errors occurred",
 "nInserted"=>2,
 "writeErrors"=>
  [{"index"=>1,
    "code"=>11000,
    "errmsg"=>
     "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.cakes.$_id_  dup key: { : \"strawberry\" }"},
   {"index"=>3,
    "code"=>11000,
    "errmsg"=>
     "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.cakes.$_id_  dup key: { : \"chocolate\" }"}]}

批量操作是必經之路。 我接受ranman的回答,但我認為我應該分享自己的最終代碼:

def insert_documents(collection_name, documents)
  collection = db[collection_name]

  bulk = collection.initialize_unordered_bulk_op
  inserts = 0

  documents.each { |doc|
    bulk.insert doc

    inserts += 1
  }

  begin
    bulk.execute
  rescue Mongo::BulkWriteError => e
    inserts = e.result["nInserted"]
  end

  return inserts
end

def insert_cakes(cakes)
  ensure_cake_indexes

  doc_list = cakes.map { |cake|
    mongofy_values(cake.to_hash)
  }

  return insert_documents(CAKE_COLLECTION, doc_list)
end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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