Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reference an embedded document in Mongoid?

Tags:

Using Mongoid, let's say I have the following classes:

class Map   include Mongoid::Document    embeds_many :locations end  class Location   include Mongoid::Document    field :x_coord, :type => Integer   field :y_coord, :type => Integer    embedded_in      :map, :inverse_of => :locations end   class Player   include Mongoid::Document    references_one   :location end 

As you can see, I'm trying to model a simple game world environment where a map embeds locations, and a player references a single location as their current spot.

Using this approach, I'm getting the following error when I try to reference the "location" attribute of the Player class:

Mongoid::Errors::DocumentNotFound: Document not found for class Location with id(s) xxxxxxxxxxxxxxxxxxx. 

My understanding is that this is because the Location document is embedded making it difficult to reference outside the scope of its embedding document (the Map). This makes sense, but how do I model a direct reference to an embedded document?

like image 564
Scott Brown Avatar asked Oct 08 '10 12:10

Scott Brown


People also ask

How do I access an embedded document in MongoDB?

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.

How do you match a nested field in MongoDB?

MongoDB Nested Query Match on a Nested Field You can use the dot notation (“field. nestedField”) to specify query criteria for fields in embedded/nested documents. For queries that use dot notation, fields and nested fields must be enclosed in double-quotes.


1 Answers

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...

like image 126
Dave Rapin Avatar answered Sep 20 '22 07:09

Dave Rapin