2015-09-04 3 views
0

У меня возникли проблемы с созданием документа Mongoid, который содержит массив пользовательских объектов.Обработка массивов пользовательских объектов в Mongoid

В моем конкретном случае я намерен хранить массив объектов BaseDevice. Класс BaseDevice уже расшифрован и сериализуется от/до простого хэша с помощью поддержки Mongoid custom fields. Это очень хорошо работает на одном объекте.

Для хранения массива BaseDevice, я создал следующий класс:

class BaseDeviceArray < Array 
    class << self 
    def demongoize(object) 
     object ? object.map{ |obj| BaseDevice.demongoize obj } : new 
    end 

    def evolve(object) 
     case 
     when BaseDeviceArray then object.mongoize 
     else object 
     end 
    end 
    end 

    def mongoize 
    self.map(&:mongoize) 
    end 
end 

Mongoid документ выглядит следующим образом

class MongoPeriph 
    include Mongoid::Document 
    field :devices, type: BaseDeviceArray 
end 

Допустим some_devices массив, содержащий два BaseDevice экземпляров. Происходит следующее: когда я назначаю some_devices полям устройств экземпляра MongoPeriph, который работает правильно.

mp = MongoPeriph.create 
mp.devices = some_devices 
mp.devices # => [#<BaseDevice:0x007fa84bac0080>,#<BaseDevice:0x007fa84baaff78>] 

При попытке отправить push, pop, shift, unshift методы в области устройств в Mongoid документе, ничего не кажется, происходит. Изменения не отображаются на объекте mp. Также при ссылке на один из объектов по индексу (т. Е. При вызове mp.devices[0].some_method) мир не изменяется.

Когда popping объектов из массива, на каждый pop дан новый объект. Ожидается, что десериализатор создает экземпляр нового объекта BaseDevice для каждого pop, но внутреннее поле не обновляется, то есть объект остается там, и можно бесконечно всплывать.

Использование BaseDeviceArray отдельно от Mongoid документа работает, как ожидалось:

foo = BaseDeviceArray.new 
foo << BaseDevice.new 

результаты в массиве с объектом BaseDevice.

КПП. Я нашел в этом другом approach. Это более обобщенный способ реализовать то, что мне нужно, но это monkey-patches Mongoid. Что-то я стараюсь избегать. Более того, это решение, похоже, имеет ту же проблему, что и мой подход.

+0

Добавление этих отношений привело к 'NoMethodError: undefined method '[]' для nil: NilClass из' ... '/mongoid-4.0.2/lib/mongoid/relations/accessors.rb: 113: in 'needs_no_database_query?' 'Кажется, он хочет, чтобы я полностью «mongoize» класса BaseDevice (и производного) с полями и т. Д. То, что я _trying_, чтобы достичь должен иметь простой объект (в массиве), встроенный в файл mongoid. – Rogier

+0

Я не знаю точно, что квалифицирует объект для возможности его встроить в документ. Я полагал, что присутствующие методы de/mogoize должны сделать его «квалифицированным» объектом mongo. В то же время я более или менее работаю со встроенными отношениями. Я забыл добавить 'super' в' BaseDevice'initializer, который отбросил мангоид с его трека. После включения «Mongoid :: Attributes :: Dynamic» это работает. Во всяком случае, я предпочел бы иметь «простой» объект без всякого монго-беспорядка. – Rogier

ответ

0

Проблема в вашем коде заключается в том, что у вас есть метод #mongoize (экземпляр), но вам действительно нужен метод ::mongoize (класс). Вы никогда не создаете экземпляр BaseDeviceArray, поэтому методы экземпляра бесполезны.

Вот пример того, как я применил метод ::mongoize, где у меня на самом деле есть mongo Hash с одним ключом со значением массива. Также я хотел сделать результирующий массив в хеш с идентификаторами как ключами для более удобного поиска.

def demongoize(hash) 
    return validate_hash(hash)["TestRecord"].each_with_object({}) do |r, m| 
    rec = TestRecord.new(r) 
    m[rec.case_id] = rec 
    end 
end 

def mongoize(object) 
    case object 
    when Array then {"TestRecord" => object.map(&:mongoize)} 
    when Hash 
    if object["TestRecord"] 
     # this gets actually called when doing TestRun.new(hash) 
     mongoize(demongoize(object)) 
    else 
     {"TestRecord" => object.values.map(&:mongoize)} 
    end 
    else raise("dunno how to convert #{object.class} into records JSON") 
    end 
end 

def evolve(object) 
    # can't see how we want to process this here yet 
    # docs.mongodb.com/ruby-driver/master/tutorials/6.0.0/mongoid-documents 
    object 
end 

Я думаю, что задача op сделана давно, но подумал, что кто-то может сочтет это полезным.

Смежные вопросы