Как ссылаться на внедренный документ в Mongoid? - PullRequest
22 голосов
/ 08 октября 2010

Используя 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

Как вы можете видеть, я пытаюсь смоделировать среду простого игрового мира, где карта встраивает местоположения, а игрок ссылается наодиночное местоположение как их текущее место.

Используя этот подход, я получаю следующую ошибку, когда пытаюсь сослаться на атрибут "location" класса Player:

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

Мое пониманиезаключается в том, что это связано с тем, что документ Location внедрен, что затрудняет ссылки за пределы области его встраиваемого документа (Карта).Это имеет смысл, но как мне смоделировать прямую ссылку на внедренный документ?

Ответы [ 5 ]

17 голосов
/ 13 ноября 2010

Поскольку Карты представляют собой собственную коллекцию, вам нужно будет выполнить итерацию по каждой коллекции Карт, в которой выполняется поиск Места, на которое ссылается ваш Игрок.

Вы не можете получить доступ к встроенным документам напрямую.Вы должны войти в коллекцию и продолжить свой путь вниз.

Чтобы избежать итерации всех Карт, вы можете сохранить как ссылку на местоположение, так и ссылку на карту в вашем документе Player.Это позволяет вам связать критерии, которые выбирают вашу карту, а затем местоположение в ней.Вы должны написать метод в своем классе Player, чтобы справиться с этим.

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

Итак, аналогично тому, как вы ответили сами, за исключением того, что вы все равно можете сохранить location_id в своем документе игрока, вместо того чтобы использовать атрибуты ord.1008 *

Другим способом было бы поместить Карты, Местоположения и Игроков в свои собственные коллекции вместо встраивания Местоположения в свою коллекцию Карт.Тогда вы могли бы использовать ссылочные отношения, не делая ничего сложного ... однако на самом деле, если вы просто используете иерархическую базу данных, на данный момент это реляционная база данных ...

11 голосов
/ 31 декабря 2010

ПОЖАЛУЙСТА, иди и проголосуй за функцию "виртуальных коллекций" в системе отслеживания проблем MongoDB:

http://jira.mongodb.org/browse/SERVER-142

Это вторая наиболее востребованная функция, но она еще не запланирована к выпуску. Может быть, если за него проголосует достаточное количество людей и он переместится на первое место, команда MongoDB, наконец, осуществит это.

6 голосов
/ 05 марта 2011

В моем случае для внешнего объекта нет необходимости ссылаться на внедренный документ.Из группы пользователей mongoid я нашел решение: используйте referenced_in во встроенном документе и НЕТ ссылки на внешний документ.

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
0 голосов
/ 17 апреля 2013

Думая нестандартно, вы можете сделать Location своим собственным документом и использовать Mongoid Alize для автоматического создания встроенных данных в вашем документе карты из ваших документов Location.

https://github.com/dzello/mongoid_alize

Преимуществоэтот метод заключается в том, что вы получаете эффективные запросы, когда условия подходят, и медленные запросы на основе ссылок к исходному документу, когда другого пути нет.

0 голосов
/ 08 октября 2010

Мой текущий обходной путь - сделать следующее:

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

Это работает, но похоже на клюге.

...