Запрос встроенных объектов в 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, и это, вероятно, лучший способ сделать то, что вам нужно, но код выше будет работать пока.