7

У меня есть две модели Content и ContentType. В модели содержимого я могу сделать:«Не равный» с именем scope в рельсах с Mongoid

def get_all_content_except_poking_message 
    Content.all.where(:name.ne => "no forking, just poking") 
end 

Теперь я пытаюсь применить область содержимого ContentType. Материалы модели снова:

# Associations 
belongs_to :content_type 

def get_all_content_except_certain_content_type(content_type) 
    Content.all.where(:content_type.name.ne => content_type) 
end 

но ошибка говорит о том, что его неправильно синтаксис применить сферу на поле объединения.

Каков правильный способ применения области применения в области ассоциации в модели?

Также я использую драгоценный камень has_scope. Могу ли я применить тот же фильтр в контроллере? Что-то вроде:

@contents = apply_scopes(
    if params[:type] 
    @content_type = ContentType.find_by_slug(params[:type]) 
    @content_type.contents.all 
    else 
    Content.all.where (:content_type.name.ne => "blogs") 
    end 
) 

Update

Для уточнения, здесь IRB выход:

irb(main):020:0> ContentType.all(:name=>"blogs").count 
=> 1 

irb(main):023:0> Content.last.content_type.name 
=> "blogs" 

irb(main):024:0> Content.all.where(:content_type => {:name => {'$ne' => "blogs"}}).count 
=> 0 

irb(main):026:0> Content.all.count 
=> 4 

ответ

5

Быстрый ответ, что запрос сервера MongoDB работает только на одной коллекции. Нет объединения, которое пересекает коллекции. Вы запрашиваете коллекцию содержимого, но указываете поле, которое находится в коллекции content_types.

Вы можете использовать вложение, чтобы поместить две модели в одну коллекцию, а затем ваш запрос может работать против поля встроенного документа (под).

Я могу предоставить более подробную информацию, если хотите, но, надеюсь, это поможет вам преодолеть нынешнее удивление.

Добавление в соответствии с просьбой, не внедряя:

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

Следующий пример основан на том, что я мог извлечь из вашего сообщения, с изменениями в работе, которые вы хотите использовать для своих методов. В запросе «нет равных» используется знание реализации ассоциации, которое является просто быстрым ответом на данный момент, но структура ссылок довольно очевидна из проверки. Также обратите внимание, что фактические запросы мопедов в MongoDB отображаются в соответствующем журнале Rails.

Я не знаком с подробностями plataformatec/has_scope. У Mongoid есть свои области, которые вы должны исследовать, я готов помочь, когда вы доберетесь туда.

приложение/модели/content_type.rb

class ContentType 
    include Mongoid::Document 
    field :name, type: String 
    has_many :contents 
end 

приложение/модели/content.rb

class Content 
    include Mongoid::Document 
    field :name, type: String 
    belongs_to :content_type 

    def self.get_all_content_except_poking_message 
    Content.where(:name.ne => "no forking, just poking") 
    end 

    def self.get_all_content_except_certain_content_type(content_type_name) # 2 queries - one each for ContentType and Content 
    content_type = ContentType.where(:name => content_type_name).first 
    Content.where(:content_type_id.ne => content_type.id) 
    end 
end 

тест/блок/content_test.Р.Б.

требуют 'test_helper'

class ContentTest < ActiveSupport::TestCase 
    def setup 
    Content.delete_all 
    ContentType.delete_all 
    end 

    test "not equal blogs" do 
    blogs = ContentType.create(:name => "blogs") 
    tweets = ContentType.create(:name => "tweets") 
    blogs.contents << Content.create(:name => "no forking, just poking") 
    tweets.contents << Content.create(:name => "Kilroy was here") 
    assert_equal 2, ContentType.count 
    assert_equal 2, Content.count 
    puts "all content_types: #{ContentType.all.to_a.inspect}" 
    puts "all contents: #{Content.all.to_a.inspect}" 
    puts "get_all_content_except_poking_message: #{Content.get_all_content_except_poking_message.to_a.inspect}" 
    puts "get_all_content_except_certain_content_type(\"blogs\"): #{Content.get_all_content_except_certain_content_type("blogs").to_a.inspect}" 
    end 
end 

тест грабли

Run options: 

# Running tests: 

[1/1] ContentTest#test_not_equal_blogsall content_types: [#<ContentType _id: 51ded9d47f11ba4ec1000001, name: "blogs">, #<ContentType _id: 51ded9d47f11ba4ec1000002, name: "tweets">] 
all contents: [#<Content _id: 51ded9d47f11ba4ec1000003, name: "no forking, just poking", content_type_id: "51ded9d47f11ba4ec1000001">, #<Content _id: 51ded9d47f11ba4ec1000004, name: "Kilroy was here", content_type_id: "51ded9d47f11ba4ec1000002">] 
get_all_content_except_poking_message: [#<Content _id: 51ded9d47f11ba4ec1000004, name: "Kilroy was here", content_type_id: "51ded9d47f11ba4ec1000002">] 
get_all_content_except_certain_content_type("blogs"): [#<Content _id: 51ded9d47f11ba4ec1000004, name: "Kilroy was here", content_type_id: "51ded9d47f11ba4ec1000002">] 
Finished tests in 0.046370s, 21.5657 tests/s, 43.1313 assertions/s. 
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips 

Для этого простого случая, вы можете "упростить" путем отхода от строгой реляционной нормализации, например, просто добавить "content_type_name" в поле «Содержимое» со строковыми значениями, например «блоги».

Но для того, чтобы действительно воспользоваться преимуществами MongoDB, вы не должны стесняться вставлять.

Надеюсь, что это поможет.

+0

Гэри, спасибо за ваш ответ. Если встроенная ассоциация не является опцией, есть ли другой способ издеваться над ассоциацией? Было бы очень полезно, если бы вы предоставили некоторый код, ориентированный на мой сценарий, в качестве примера. :) – Annie

+0

Annie, пример в ответе выше нацелен на ваш сценарий, используя ссылки/ссылки, а не встраивание. Изучите код Content :: get_all_content_except_certain_content_type, который точно отвечает на ваш вопрос с помощью двухэтапной выборки, которая необходима. –

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