Reputation: 4169
class Foo
include Mongoid::Document
field :name, type: String
embeds_many :bars
end
class Bar
include Mongoid::Document
field :name, type: String
embedded_in :foo
end
Is there a way that I can query all of the bars
here? In AR I'd do something like Bar.where(name: 'something')
- just give me all the bars that match some criteria.
As it stands, I can only query the specific bars on a single foo. `Foo.first.bars.where(name: 'something'). I know mongoDB has no joins, so... I'm curious how to go about this.
I'm about ready to lose the Foo all together and do something like:
class Bar
include Mongoid::Document
field :foo_name, type: String
field :name, type: String
end
Upvotes: 7
Views: 7289
Reputation: 1615
You are not able to return Bar
object without first returning the Foo
object it is embedded in.
You can query for a top level document (Foo
) as matches for embedded documents.
foo = Foo.create(:name => 'foo1')
foo.bars << Bar.new(:name => 'bar1')
Foo.where(:'bars.name' => 'bar1').first
=> #<Foo _id: 53c4a380626e6f813d000000, name: "foo1">
Then once you have the Foos that match some embedded bar, you can find the bar you are looking for with another query (which just maps to an Array#find
or Array#select
foo.bars << Bar.new(:name => 'bar2')
Foo.where(:'bars.name' => 'bar1').first.bars.where(:name => 'bar2').first
=> #<Bar _id: 53c4a380626e6f813d000001, name: "bar2">
Update: In cases where you are querying for the embedded document out of the parent document context, I recommend against the use of an embedded document. When you embed a document, you are saying "I do not intend for the document to exist on it's own". If you find yourself query for it directly then ditch the embedding. It is tempting to embed but typically you don't need/require it.
Note: I have de-embedded 100M+ entries and it was a long hectic process.
Note2: embedding some metadata or aggregate is an optimization best kept for times when you really need it
Upvotes: 11