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
Accessing embedded/nested documents – In MongoDB, you can access the fields of nested/embedded documents of the collection using dot notation and when you are using dot notation, then the field and the nested field must be inside the quotation marks.
Use the Array Index to Query for a Field in the Embedded Document. Using dot notation, you can specify query conditions for field in a document at a particular index or position of the array. The array uses zero-based indexing. When querying using dot notation, the field and index must be inside quotation marks.
MongoDB provides you a cool feature which is known as Embedded or Nested Document. Embedded document or nested documents are those types of documents which contain a document inside another document.
To query if the array field contains at least one element with the specified value, use the filter { <field>: <value> } where <value> is the element value. To specify conditions on the elements in the array field, use query operators in the query filter document: { <array field>: { <operator1>: <value1>, ... } }
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With