Это сложно (или невозможно) сделать с помощью одного запроса. Я играл с этим некоторое время. Прежде всего, позвольте мне опубликовать весь мой тестовый скрипт:
require 'mongoid'
Mongoid.configure do |config|
config.master = Mongo::Connection.new.db("test")
end
class Box
include Mongoid::Document
embeds_many :things
field :name
end
class Thing
include Mongoid::Document
field :title
field :value, type: Integer
end
b = Box.new
b.name = "non sock box"
b.things.push Thing.create!(title: "Ring", value:1)
b.save!
b1 = Box.new
b1.name = "sock box"
b1.things.push Thing.create!(title:"Socks", value:50)
b1.save!
b2 = Box.new
b2.name = "huge sock box"
b2.things.push Thing.create!(title:"Socks", value:1000)
b2.things.push Thing.create!(title:"Ring", value:1100)
b2.save!
b3 = Box.new
b3.name = "huge ring box"
b3.things.push Thing.create!(title:"Socks", value:100)
b3.things.push Thing.create!(title:"Ring", value:2600)
b3.save!
b4 = Box.new
b4.name = "ring first sock box"
b4.things.push Thing.create!(title: "Ring", value: 1200)
b4.things.push Thing.create!(title: "Socks", value: 5)
b4.save!
Итак, вы делаете это несколькими способами. Во-первых, вы можете найти все объекты Thing, которые соответствуют вашим критериям, а затем что-то сделать с Things. Например, получите Box ID.
Thing.desc(:value).where(:title => "Socks").to_a
Это переносит проблему на уровень приложения, что типично для некоторых запросов монго. Но это не то, что вы просили. Поэтому я отправляю этот неприятный запрос. Это работает, только если у вас всегда есть вещи Sock во встроенном документе.
Box.all(conditions: { "things.title" => "Socks" },
sort:[["things.0.value", :desc]]).to_a
Что действительно раздражает, потому что вы заметите, что в моих примерах данных у меня есть «огромный кольцевой ящик», который имеет носки, но также имеет атрибут наибольшего значения, так что фактически он возвращается первым. Если вы пересортируете вещи, этот запрос на самом деле будет работать. Я не знаю, как сказать, сортировать по вещей.значению, равному "foo". Держу пари, ты не можешь.
>> Box.all(conditions: { "things.title" => "Socks" },
sort:[["things.0.value", :desc]]).collect(&:name)
=> ["ring first sock box", "huge sock box", "huge ring box", "sock box"]
Видите, это неправильно. Огромная коробка носка должна быть первой. Но это не из-за вещей. 0 выбирает самое большое значение кольца 2600 в (b4) образца данных.
Вы можете заставить работать один лайнер, но он фактически выполняет (как минимум) два запроса:
Thing.desc(:value).where(:title => "Socks").collect(&:id).each {|thing|
puts Box.where("things._id" => thing).first.name }
Но опять же, это действительно делает лифтинг в рубине, а не монго. Есть много таких проблем с присоединением. Вы должны сделать два запроса.
Другой вариант может состоять в том, чтобы нормализовать ваши данные и просто сохранить вещи как встроенный массив атрибутов или просто атрибутов. Если сундуки могут содержать что-либо, вам даже не нужно определять атрибуты заранее. Это классная вещь в MongoDB.
class Chest
include Mongoid::Document
field :name
end
c = Chest.create!(:name => "sock chest", :socks => 50, :ring => 1)
c1 = Chest.create!(:name => "non sock chest", :ring => 10)
c2 = Chest.create!(:name => "huge sock chest", :ring => 5, :socks => 100)
c3 = Chest.create!(:name => "huge ring chest", :ring => 100, :socks => 25)
Chest.where(:socks.exists => true).desc(:socks).collect(&:name)
=> ["huge sock chest", "sock chest", "huge ring chest"]