mongo-ruby-driver icon indicating copy to clipboard operation
mongo-ruby-driver copied to clipboard

RUBY-3355 - Create when key '_id' (as string) is nil results in error

Open DrissTM opened this issue 7 months ago • 2 comments

Hi!

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.


Let me know if I should create an issue in JIRA first

DrissTM avatar Nov 16 '23 18:11 DrissTM