Reported on GitHub with PR - https://github.com/mongodb/mongo-ruby-driver/pull/2808
While investigating an issue in an application I'm working on I discovered that trying to insert a document containing '_id' => nil will raise the following exception:
.../lib/mongo/operation/result.rb:364:in `raise_operation_failure': [2]: can't have multiple _id fields in one document (on 127.0.0.1:27017, legacy retry, attempt 1) (Mongo::Error::OperationFailure)
Here's a reproduction script:
require 'bundler/inline' gemfile do source 'https://rubygems.org' gem 'mongo' end client = Mongo::Client.new(['127.0.0.1:27017'], database: 'PoC_DTM') # Assuming you have a mongo server running on port 27017 db = client.database collection = db[:fake_collection] collection.insert_one({ field: 'test', _id: nil }) # => OK collection.insert_one({ field: 'test', '_id' => nil }) # => KO
I was able to track down the issue in the lib/mongo/operation/shared/idable.rb file:
... def id(doc) doc.respond_to?(:id) ? doc.id : (doc['_id'] || doc[:_id]) end def has_id?(doc) !!id(doc) end def ensure_ids(documents) @ids= [] documents.collect do |doc| doc_with_id = has_id?(doc) ? doc : doc.merge(_id: id_generator.generate) @ids<< id(doc_with_id) doc_with_id end end ...
When '_id' is equal to nil has_id? returns false which causes ensure_ids to generate an id that it stores in :_id but without removing the '_id' key which results in the document having both '_id' and :_id, hence the exception mentioned above.
- links to