Запрос встроенных объектов в Mongoid/rails 3 ( "Lower than", Min operator and sorting)

Я использую рельсы 3 с мангоидом. У меня есть коллекция акций со встроенной коллекцией цен:

class Stock
  include Mongoid::Document
  field :name, :type => String
  field :code, :type => Integer
  embeds_many :prices

class Price
  include Mongoid::Document
  field :date, :type => DateTime
  field :value, :type => Float
  embedded_in :stock, :inverse_of => :prices

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

Но похоже, что Mongodb не позволяет это делать. Потому что это не сработает:

@stocks = Stock.Where(:prices.value.lt => p)

Кроме того, похоже, что mongoDB не может сортировать внедренные объекты.

Итак, есть ли альтернатива для выполнения этой задачи?

Может быть, я должен поместить все в одну коллекцию, чтобы я мог легко запустить следующий запрос:

@stocks = Stock.Where(:prices.lt => p)

Но я действительно хочу получить результаты, сгруппированные по именам акций после моего запроса (например, отдельные запасы с массивом упорядоченных цен). Я слышал о карте/сокращении с помощью групповой функции, но я не уверен, как правильно ее использовать с Mongoid.

http://www.mongodb.org/display/DOCS/Aggregation

Эквивалент в SQL будет примерно таким:

SELECT name, code, min(price) from Stock WHERE price<p GROUP BY name, code

Спасибо за вашу помощь.

Ответы

Ответ 1

MongoDB/Mongoid действительно позволяет это делать. Ваш пример будет работать, синтаксис просто неверен.

@stocks = Stock.Where(:prices.value.lt => p) #does not work

@stocks = Stock.where('prices.value' => {'$lt' => p}) #this should work

И он по-прежнему подключается, поэтому вы можете заказать по имени:

@stocks = Stock.where('prices.value' => {'$lt' => p}).asc(:name)

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

Ответ 2

У меня была аналогичная проблема... вот что я предлагаю:

scope :price_min, lambda { |price_min| price_min.nil? ? {} : where("price.value" => { '$lte' => price_min.to_f }) }

Поместите эту область в родительскую модель. Это позволит вам задавать такие запросы, как:

Stock.price_min(1000).count

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

Удачи!

Очень хорошо, Рюи

Ответ 3

MongoDB делает разрешает запрос встроенных документов, http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanEmbeddedObject

То, что вам не хватает, - это область на модели цены, что-то вроде этого:

 scope :greater_than, lambda {|value| { :where => {:value.gt => value} } }

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

 prices.sort {|a,b| a.value <=> b.value}.each {|price| puts price.value}

Mongoid имеет метод map_reduce, с помощью которого вы передаете две строковые переменные, содержащие функции Javascript, для выполнения map/reduce, и это, вероятно, лучший способ сделать то, что вам нужно, но код выше будет работать пока.