Sherwin Yu
Sherwin Yu

Reputation: 3230

Mongoid embedded document returning empty for queries

When I query the embedded model, no records are returned despite there being plenty of parent records containing instances of the embedded model.

There are two models, a Label embedded in a Band:

class Band
  include Mongoid::Document
  embeds_one :label
end

class Label
  include Mongoid::Document
  field :name, type: String
  embedded_in :band
end

I can query Band (Band.all, Band.find etc) just fine, but when I query Label, it returns nothing. For instance:

I create the band with the embedded label, and save it:

 > b = Band.create
 => #<Band _id: 516cff525543d8842e000008, _type: nil>
 > b.build_label name: "new label"
 => #<Label _id: 516cff5a5543d8842e000009, _type: nil, name: "new label">
 > b.save
 => true

Then I query the Band model, and all is fine:

 > Band.all.to_a
 => [#<Band _id: 516cff525543d8842e000008, _type: nil>]
 > Band.count
 => 1
 > Band.first.label
 => #<Label _id: 516cff5a5543d8842e000009, _type: nil, name: "new label">
 > Band.find "516cff525543d8842e000008"
 => #<Band _id: 516cff525543d8842e000008, _type: nil>

But when I query the Label model, nothing shows up!

 > Label.all.to_a
 => []
 > Label.count
 => 0
 > Label.last
 => nil
 > Label.first
 => nil
 > Label.find "516cff5a5543d8842e000009" # this is the label id from Band
 => nil

I'm almost positive this is not intended behavior. The code is directly from an example on the Mongoid docs here: http://mongoid.org/en/mongoid/docs/relations.html#embeds_one

What am I missing?

Upvotes: 1

Views: 1063

Answers (2)

Frank C. Schuetz
Frank C. Schuetz

Reputation: 714

In mongo your queries always target collections, i.e. full documents that may embed other documents. For mongo it's just one big JSON/BSON document. Now, Label.all or Label.all are equivalent to querying the Label collection. Since labels are not stored in the Label collection, those queries return nothing. However, you can still query labels on the Band collection by calling

Band.where(:'labels._id' => "516cff5a5543d8842e000009")

or something like

Band.where(:'labels.name' => "rock")

This is fine if you want to get all bands with a certain label. Getting all labels this way, however, is very expensive and not recommended. What's your main use case? If it is showing labels for a band or getting bands with a certain label, then embedding is great. Otherwise, you could use relations (has_many/belongs_to), or denormalize completely, i.e. save labels within bands and in a separate collection at the same time (leading to redundant data).

Upvotes: 2

oivoodoo
oivoodoo

Reputation: 794

I think you should use has_many, has_one, belongs_to methods for making possible to run queries as you want like Label.count.

When you embed document into another document it will become as a part(serialized property) of a document. If you want to select labels you should find Band at first and then check the label property. It should definitely work.

Upvotes: 0

Related Questions