2013-05-09 7 views
1

Скажем, у меня есть User с полем name и который has_many teams, и Team что BELONGS_TO в user и belongs_to в sport. A Sport имеет поле name и has_many teams.Как сортировать по вложенному значению поля с помощью Mongoid?

Я хочу, чтобы пройти через sports, делать некоторые вещи, и собрать массив из teams отсортированных по name в user.

result = [] 
Sport.asc(:name).each do |spt| 
    # some other stuff not relevant to this question but that 
    # justifies my looping through each sport. 
    spt.teams.asc(:'user.name').each { |t| result << t } 
end 

Это работает, но и сортировка sports будет, как ожидается, но порядок команд в result не сортируется, как я ожидал.

Каков правильный способ, используя Mongoid для сортировки коллекции по значению отношения?

ответ

3

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

Я думаю, вы, вероятно, есть два варианта, тем менее эффективным способом было бы просто отсортировать коллекцию команд в рубин:

sport.teams.sort{|t1, t2| t1.user.name <=> t2.user.name}.each{ |team| result << team } 

тем лучше, и, возможно, более «MongoDB-у» решение, будет будет кэшировать имя пользователя внутри каждой команды, используя before_save обратного вызова, а затем использовать его для сортировки команд:

# app/models/team.rb 
class Team 
    include Mongoid::Document 

    field :user_name, :type => String 

    before_save :update_user_name 

    protected 
    def update_user_name 
    self.user_name = self.user.name if self.user 
    end 
end 

Тогда вы можете просто сделать:

spt.teams.asc(:user_name).each { |t| result << t } 

Очевидно, что если поле имени пользователя изменчиво, вы должны вызвать его для сохранения каждой дочерней команды всякий раз, когда изменяется имя поля пользователя.

class User 
    after_save :update_teams_if_name_changed 

    def update_teams_if_name_changed 
    if self.name_changed? 
     self.teams.each { |team| team.save } 
    end 
    end 
end 

Учитывая, что это не фантастически прост в обслуживании, это возможно, могла бы быть хорошим кандидатом для использования наблюдателя, а не обратных вызовов, но вы получите идею.

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

  • Нет связанных вопросов^_^