Как ссылаться на встроенный документ в Mongoid?
Вопрос
Использование монгоида, скажем, у меня есть следующие классы:
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
Как видите, я пытаюсь моделировать простую игровую мировую среду, где карта встраивает местоположения, а игрок ссылается на одно местоположение как их текущее место.
Используя этот подход, я получаю следующую ошибку, когда я пытаюсь ссылаться на атрибут «местоположения» класса плеера:
Mongoid::Errors::DocumentNotFound: Document not found for class Location with id(s) xxxxxxxxxxxxxxxxxxx.
Мое понимание состоит в том, что это потому, что документ местоположения встроен, что затрудняет ссылку за пределами объема его встраиваемого документа (карта). Это имеет смысл, но как мне представить прямую ссылку на встроенный документ?
Решение
Поскольку карты являются их собственной коллекцией, вам нужно будет повторять каждую коллекцию карты в поисках внутри местонахождения, на который ссылается, на который ссылается ваш игрок.
Вы не можете получить доступ к встроенным документам напрямую. Вы должны войти через коллекцию и работать вниз.
Чтобы избежать итерации всех отображений, вы можете хранить как ссылку на местоположение, так и ссылку на карту в документе вашего игрока. Это позволяет вам цепи критерии, которые выбирают вашу карту, а затем местоположение внутри него. Вы должны кодировать метод в классе вашего игрока, чтобы обработать это.
def location
self.map.locations.find(self.location_id)
end
Итак, похоже на то, как вы ответили на себя, за исключением того, что вы все равно можете хранить местоположение_id в своем документе Player, а не использовать атрибуты координат.
Еще один способ поставить карты, места и игроки в свои собственные коллекции вместо того, чтобы встроить местоположение в вашей карте. Тогда вы можете использовать ссылочные отношения, не делая ничего фантазии ... Однако вы действительно просто используете иерархическую базу данных, это нравится реляционная база данных в этой точке ...
Другие советы
Пожалуйста, проготайте и голосуйте за функцию «Виртуальные коллекции» на выпуске MongoDB Tracker:
http://jira.mongodb.org/browse/server-142.
Это 2-я самая запрошенная функция, но она все еще не была запланирована для выпуска. Может быть, если достаточно людей проголосуют за это и переместите его на номер один, команда MongoDB, наконец, будет реализовать ее.
В моем случае в случае использования внешнего объекта нет необходимости ссылаться на встроенный документ. Из группы пользователей Mongoid я нашел решение: используйте ссылку на ссылку на встроенный документ и без ссылки на внешний документ.
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
Мой текущий обходной путь состоит в том, чтобы сделать следующее:
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
Это работает, но чувствует себя как kluge.
Думая за пределами коробки, вы можете создать местоположение собственным документом и использовать Mongoid Alize, чтобы автоматически генерировать встроенные данные в документ вашей карты из ваших документов о местоположении.
https://github.com/dzello/mongoid_alize.
Преимущество этого метода заключается в том, что вы получаете эффективные запросы, когда условия подходят, и более медленные ссылочные запросы на исходном документе, когда нет другого способа.