0

I need to search within Mongoid objects that have array attributes. Here are the relevant objects:

class Author
  include Mongoid::Document
  field :name, type: String

class Book
  include Mongoid::Document
  field :name, type: String
  field :authors, type: Array

I can see that at least one book has a given author:

Book.all.sample.authors
=> [BSON::ObjectId('5363c73a4d61635257805e00'),
 BSON::ObjectId('5363c73a4d61635257835e00'),
 BSON::ObjectId('5363c73a4d61635257c75e00'),
 BSON::ObjectId('5363c73b4d616352574a5f00')]

But I'm unable to find books that have that author.

Book.where(authors: '5363c73a4d61635257805e00').first
=> nil

I've tried the solution listed here: https://groups.google.com/forum/#!topic/mongoid/csNOcugYH0U but it didn't work for me:

Book.any_in(:author => ["5363c73b4d616352574a5f00"]).first
=> nil

I'm not sure what I'm doing wrong. Any ideas? I'd prefer to use Mongoid Origin commands.

1 Answer 1

1

This output:

Book.all.sample.authors
=> [BSON::ObjectId('5363c73a4d61635257805e00'),
 BSON::ObjectId('5363c73a4d61635257835e00'),
 BSON::ObjectId('5363c73a4d61635257c75e00'),
 BSON::ObjectId('5363c73b4d616352574a5f00')]

tells us that authors contains BSON::ObjectIds. ObjectIds are often presented as Strings and sometimes you can use a String instead of a full blown ObjectId (such as with Model.find) but they're still not Strings. You are searching the array for a String:

Book.where(authors: '5363c73a4d61635257805e00')

but '5363c73a4d61635257805e00' and ObjectId('5363c73a4d61635257805e00') are not the same thing inside MongoDB. You need to search for the right thing:

Book.where(authors: BSON::ObjectId('5363c73a4d61635257805e00'))

You might want to monkey patch a to_bson_id method into various places. Something like this:

class String
  def to_bson_id
    BSON::ObjectId.from_string(self)
  end
end

module Mongoid
  module Document
    def to_bson_id
      id
    end
  end
end

module BSON
  class ObjectId
    def to_bson_id
      self
    end
  end
end

class NilClass
  def to_bson_id
    self
  end
end

Should do the trick. Then you can say things like:

Book.where(authors: '5363c73a4d61635257805e00'.to_bson_id)
Book.where(authors: some_string_or_object_id.to_bson_id)

and The Right Thing happens.

You might want to rename authors to author_ids to make its nature a little clearer.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks mu! I've used so many of your answers in the past. I ultimately needed to use the BSON::ObjectId.from_string(self), and I've updated your code accordingly.
Thanks for the from_string fix, I've been using Mongoid/Moped for awhile.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.