Odpytywanie osadzonych obiektów w Mongoid/rails 3 ("Lower than", operatory Min i sortowanie)

Używam rails 3 z mongoid. Mam zbiór akcji z wbudowanym zbiorem cen:

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

Chciałbym uzyskać zapasy, których cena minimalna od danej daty jest niższa niż podana cena p, a następnie móc sortować ceny dla każdej akcji.

Ale wygląda na to, że Mongodb nie pozwala na to. Bo to nie zadziała:

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

Wydaje się również, że mongoDB nie może sortować osadzonych obiektów.

Więc, jest alternatywa w rozkaz do wykonania tego zadania ?

Może powinienem umieścić wszystko w jednym zbiorze, abym mógł łatwo uruchomić następujące zapytanie:

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

Ale naprawdę chcę, aby wyniki pogrupowane według nazw akcji po moim zapytaniu(różne zapasy z tablicą zamówionych cen na przykład). Słyszałem o map/reduce z funkcją group, ale nie jestem pewien, jak poprawnie z nią korzystać z Mongoid.

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

Odpowiednik w SQL byłoby coś takiego:

SELECT name, code, min(price) from Stock WHERE price<p GROUP BY name, code
Dzięki za pomoc.
Author: DanSingerman, 2011-03-10

3 answers

MongoDB / Mongoid pozwala ci to zrobić. Twój przykład zadziała, składnia jest po prostu Niepoprawna.

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

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

I nadal jest Łańcuchowy, więc możesz zamówić również po nazwie:

@stocks = Stock.where('prices.value' => {'$lt' => p}).asc(:name)
Mam nadzieję, że to pomoże.
 21
Author: Rick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-07 20:44:07

Miałem podobny problem... oto co proponuję:

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

Umieść ten zakres w modelu rodzica . To umożliwi Ci tworzenie zapytań takich jak:

Stock.price_min(1000).count

Zauważ, że mój zakres działa tylko wtedy, gdy faktycznie wstawisz tam pewne dane. Jest to bardzo przydatne, jeśli budujesz złożone zapytania za pomocą Mongoid.

Powodzenia!

Very best, Ruy

 2
Author: ruybilton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-30 04:13:17

MongoDB umożliwia odpytywanie osadzonych dokumentów, http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanEmbeddedObject

Brakuje Ci lunety na modelu cenowym, coś w tym stylu:

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

To pozwoli Ci przekazać dowolną wartość i zwrócić Mongoid zbiór cen o wartości większej niż to, co przekazałeś. To będzie niesortowana kolekcja, więc musisz ją uporządkować Ruby.

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

Mongoid ma metodę map_reduce , do której przekazujesz dwie zmienne łańcuchowe zawierające funkcje Javascript do wykonania map/reduce, i prawdopodobnie byłby to najlepszy sposób na zrobienie tego, czego potrzebujesz, ale powyższy kod będzie działał na razie.

 1
Author: Srdjan Pejic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-10 19:37:40