Запрос встроенных объектов в Mongoid / rails 3 («Ниже чем», операторы Min и сортировка) - PullRequest
16 голосов
/ 10 марта 2011

Я использую рельсы 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

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

Ответы [ 3 ]

21 голосов
/ 08 мая 2011

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 голосов
/ 30 марта 2011

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

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

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

Stock.price_min(1000).count

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

Удачи!

Отлично, Руи

1 голос
/ 10 марта 2011

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

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

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

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

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

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

...