Mongoid查询引用ID但不使用嵌入文档

时间:2012-05-22 23:08:42

标签: ruby-on-rails mongodb mongoid

我有一个Mongo集合,只是将ID引用到另一个集合。假设我特别提到的集合可能被称为:

漫游。 Walks引用了owner_id。业主每天带着许多宠物散步。我想要做的是查询Walks获取N owner_ids的列表,并且只获取他们为owner_id所拥有的每个所有者和组所采取的最后一步。要通过列表获取所有行走的列表,我们会做类似的事情。

Walk.any_in(:owner_id => list_of_ids)

我的问题是,有没有办法查询list_of_ids,每个owner_id只能获得一个步行(他们最后一个可以按字段created_at排序,并返回散列,每个步行都指向由owner_id如:

{ 5 => {..walk data..}, 10 => {.. walk data ..}}

1 个答案:

答案 0 :(得分:0)

这是一个使用MongoDB的group命令的答案。 出于测试目的,我使用了 walk_time 而不是 created_at 。 希望这有帮助,你喜欢它。

class Owner
  include Mongoid::Document
  field :name, type: String
  has_many :walks
end

class Walk
  include Mongoid::Document
  field :pet_name, type: String
  field :walk_time, type: Time
  belongs_to :owner
end

测试/单元/ walk_test.rb

require 'test_helper'

class WalkTest < ActiveSupport::TestCase
  def setup
    Owner.delete_all
    Walk.delete_all
  end

  test "group in Ruby" do
    walks_input = {
        'George' => [ ['Fido',  2.days.ago], ['Fifi',  1.day.ago],  ['Fozzy',    3.days.ago] ],
        'Helen'  => [ ['Gerty', 4.days.ago], ['Gilly', 2.days.ago], ['Garfield', 3.days.ago] ],
        'Ivan'   => [ ['Happy', 2.days.ago], ['Harry', 6.days.ago], ['Hipster',  4.days.ago] ]
    }
    owners = walks_input.map do |owner_name, pet_walks|
      owner = Owner.create(name: owner_name)
      pet_walks.each do |pet_name, time|
        owner.walks << Walk.create(pet_name: pet_name, walk_time: time)
      end
      owner
    end
    assert_equal(3, Owner.count)
    assert_equal(9, Walk.count)
    condition = { owner_id: { '$in' => owners[0..1].map(&:id) } } # don't use all owners for testing
    reduce = <<-EOS
      function(doc, out) {
        if (out.last_walk == undefined || out.last_walk.walk_time < doc.walk_time)
          out.last_walk = doc;
      }
    EOS
    last_walk_via_group = Walk.collection.group(key: :owner_id, cond: condition, initial: {}, reduce: reduce)
    p last_walk_via_group.collect{|r|[Owner.find(r['owner_id']).name, r['last_walk']['pet_name']]}
    last_walk = last_walk_via_group.collect{|r|Walk.new(r['last_walk'])}
    p last_walk
  end
end

测试输出

Run options: --name=test_group_in_Ruby

# Running tests:

[["George", "Fifi"], ["Helen", "Gilly"]]
[#<Walk _id: 4fbfa7a97f11ba53b3000003, _type: nil, pet_name: "Fifi", walk_time: 2012-05-24 15:39:21 UTC, owner_id: BSON::ObjectId('4fbfa7a97f11ba53b3000001')>, #<Walk _id: 4fbfa7a97f11ba53b3000007, _type: nil, pet_name: "Gilly", walk_time: 2012-05-23 15:39:21 UTC, owner_id: BSON::ObjectId('4fbfa7a97f11ba53b3000005')>]
.

Finished tests in 0.051868s, 19.2797 tests/s, 38.5594 assertions/s.

1 tests, 2 assertions, 0 failures, 0 errors, 0 skips