Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 841 Vote(s) - 3.49 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to reference an embedded document in Mongoid?

#1
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?
Reply

#2
Thinking outside the box, you could make Location its own document and use Mongoid Alize to automatically generate embedded data in your Map document from your Location documents.

[To see links please register here]


The advantage of this method is that you get efficient queries when conditions are suitable, and slower reference based queries on the original document when there's no other way.
Reply

#3
In my use case, there is no need for the outside object to reference the embedded document. From the mongoid user group, I found the solution: Use referenced_in on the embedded document and NO reference on the outside document.

class Page
include Mongoid::Document
field :title

embeds_many :page_objects
end

class PageObject
include Mongoid::Document
field :type

embedded_in :page, :inverse_of => :page_objects
referenced_in :sprite
end

class Sprite
include Mongoid::Document
field :path, :default => "/images/something.png"
end

header_sprite = Sprite.create(:path => "/images/header.png")
picture_sprte = Sprite.create(:path => "/images/picture.png")

p = Page.create(:title => "Home")
p.page_objects.create(:type => "header", :sprite => header_sprite)
p.page_objects.first.sprite == header_sprite

Reply

#4
PLEASE go and VOTE for the "virtual collections" feature on MongoDB's issue tracker:

[To see links please register here]


It's the 2nd most requested feature, but it still hasn't been scheduled for release. Maybe if enough people vote for it and move it to number one, the MongoDB team will finally implement it.
Reply

#5
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...
Reply

#6
My current workaround is to do the following:

class Map
include Mongoid::Document

embeds_many :locations
references_many :players, :inverse_of => :map
end

class Player
referenced_in :map
field :x_coord
field :y_coord

def location=(loc)
loc.map.users << self
self.x_coord = loc.x_coord
self.y_coord = loc.y_coord
self.save!
end

def location
self.map.locations.where(:x_coord => self.x_coord).and(:y_coord => self.y_coord).first
end
end

This works, but feels like a kluge.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through