How to Reference an Embedded Document in Mongoid

How to reference an embedded document in Mongoid?

Because Maps are their own collection, you would need to iterate over every Map collection searching within for the Location your Player is referenced.

You can't access embedded documents directly. You have to enter through the collection and work your way down.

To avoid iterating all of the Maps you can store both the Location reference AND the Map reference in your Player document. This allows you to chain criteria that selects your Map and then the Location within it. You have to code a method on your Player class to handle this.

def location
self.map.locations.find(self.location_id)
end

So, similar to how you answered yourself except you could still store the location_id in your player document instead of using the coord attribs.

Another way would be to put Maps, Locations, and Players in their own collections instead of embedding the Location in your Map collection. Then you could use reference relationships without doing anything fancy... however your really just using a hierarchical database likes it's a relational database at this point...

Retrieve an embedded document using Mongoid

Because you are using embedded documents, grabbing a single question may not make sense. It does, however, make sense in the context of the parent document. If you really just want a specific question, you can just use normal ARish syntax:

question = Question.find(params[:id])

I would strongly suggest you make sure you have an index on the question._id field. This will help ensure this query is a fast read operation. Otherwise, Mongo will need to run through all of the Equipment documents and check each of the embedded Question objects.

If the above doesn't work, you can try a nested relation:

Equipment.find(params[:equipment_id]).questions.find(params[:id])

Rails Mongoid : Query embedded document and access to Mongoid criteria

You have this in your embedded model:

field :user_id, type: String

but your query is using a BSON::ObjectId:

Travel.where('participants.user_id' => @user.id)

as shown in the raw query:

selector: {"participants.user_id"=>BSON::ObjectId('592c8da58511989ec850921e')}

Your embedded document probably has a string field like:

"user_id": "592c8da58511989ec850921e"

rather than the ObjectId you're looking for:

"user_id": ObjectId("592c8da58511989ec850921e")

so you won't find what you're looking for due to the type mismatch.

Either fix the embedded field's type:

field :user_id, type: BSON::ObjectId

or query it as the string it is:

Travel.where('participants.user_id' => @user.id.to_s)

Changing the type will involve fix up whatever data you already have, changing the query is ugly in a different way.

Sometimes Mongoid will convert between strings and ObjectIds for you, sometimes it won't. When I used Mongoid I patched to_bson_id methods into BSON::ObjectId, String, Mongoid::Document, ... so that I could say things like:

Model.where(:some_id => some_id.to_bson_id)

and not have to constantly worry about what type some_id was. I also made sure that all ID fields were always specified as BSON::ObjectId.

Referencing inside embedded documents in Mongoid

Your data structure is perfectly fine - document oriented databases are meant to be used like this. You should not repeat the address inside every activity since you will end up wasting space.

User : {
# User data,
address_<id> : {
# address data
},
address_<id> : {
# address data,
home : true
},

activity : {
# activity data,
_address_id: #referenced address within user
},
activity : {
# activity data,
_address_id: #referenced address within user
},
}

There are just two things that you need to take care of:

1. Dont retrieve the entire document for a single activity

2. Make sure that the document does not exceed the maximum size (or recompile)

mongoid - querying embedded docs

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

Self referential embedded documents using Mongoid

You cannot have references to embedded models - even when they're both embedded in the same document. If you correctly configure the relationship

belongs_to :discovered_by, :class_name => 'Bar', inverse_of: :discovered
has_one :discovered, :class_name => 'Bar', inverse_of: :discovered_by

Mongoid will raise a Mongoid::Errors::MixedRelations exception. Maybe you could reconsider if embedding these objects is still the best choice. A workaround is storing only the id and query the parent object:

class Bar
include Mongoid::Document
embedded_in :foo
field :discovered_by_id, type: Moped::BSON::ObjectId

def discovered_by
foo.bars.find(discovered_by_id) if discovered_by_id
end

def discovered_by=(bar)
self.discovered_by_id = bar.id
end
end


Related Topics



Leave a reply



Submit