1

Userwith a fieldnameと、 has_manyとteamsTeambelongs_to auserと belongs_to a があるとしsportます。ASportにはフィールドnameと has_manyがありteamsます。

をウォークスルーし、いくつかのことを行い、 の でソートされたのsports配列を収集したいと考えています。teamsnameuser

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リレーションの値でコレクションをソートする正しい方法は何ですか?

4

1 に答える 1

3

Mongoid でこれを行う方法はないと思います。並べ替え対象のフィールドが埋め込みドキュメントの一部である場合は機能する可能性がありますが、参照ドキュメントを使用している場合は機能しません。

ここにはおそらく 2 つのオプションがあると思いますが、チームのコレクションを ruby​​ でソートするのは非効率的な方法です。

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

より優れた、おそらくより「MongoDB-y」なソリューションは、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

保守が驚くほど簡単ではないことを考えると、これは間違いなく、コールバックではなくオブザーバーを使用するための良い候補になる可能性がありますが、アイデアは理解できます。

于 2013-05-09T00:24:47.047 に答える