查询 Mongoid/rails 3 中的嵌入对象(“低于”、Min 运算符和排序)

Posted

技术标签:

【中文标题】查询 Mongoid/rails 3 中的嵌入对象(“低于”、Min 运算符和排序)【英文标题】:Querying embedded objects in Mongoid/rails 3 ("Lower than", Min operators and sorting) 【发布时间】:2011-07-12 15:52:05 【问题描述】:

我正在使用带有 mongoid 的 rails 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)

但我真的想在查询后获得按股票名称分组的结果(例如,具有一系列有序价格的不同股票)。我听说过使用 group 功能的 map/reduce,但我不确定如何正确使用 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)

希望这会有所帮助。

【讨论】:

请注意,仍然可以进行更复杂的查询,例如:all_of(:'books.name' =&gt; 'name', :'books.author' =&gt; /joe/i) 使用字符串作为参数的名称对我来说很好......感谢您提供的信息,这真的很有帮助【参考方案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

您缺少的是 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 确实有一个 ma​​p_reduce 方法,您可以将两个包含 javascript 函数的字符串变量传递给该方法来执行 map/reduce,这可能是您需要的最佳方式,但是代码以上暂时可以使用。

【讨论】:

感谢您的回答。但我不确定如何使用这个范围功能。我将范围函数放在我的 Price 模型中,并查询 @Stocks = Stock.where(:prices.greater_than => 200) ,它给了我一个错误:“未定义的方法 `greater_than' for :prices:Symbol” 范围应该在单个 Stock 上调用,而不是在集合上。所以,你的代码确实行不通。因为您希望像这样进行过滤,所以最好使用 MapReduce 调用。我会看看我是否可以在某个地方发布一个示例。 是的,这就是我刚刚发现的。尽管如此,我还是找到了一个愚蠢而缓慢的解决方案,例如可以获取价格在 100 到 200 之间的股票列表,但我对此并不满意:i = 100 while i&lt;200 results = Stock.where("prices.value" =&gt; i) if(@stocks == nil) @stocks = results else @stocks += results end i += 1 end @mathieurip 的更大范围只是Stock 上的一个类方法,所以这样称呼它:Stock.greather_than

以上是关于查询 Mongoid/rails 3 中的嵌入对象(“低于”、Min 运算符和排序)的主要内容,如果未能解决你的问题,请参考以下文章

Heroku 的 Rails、Mongoid 和 Unicorn 配置

Mongoid Rails 4 按 asc 或 desc order created_at 排序

如何使用 mongoid、rails 和谷歌地图搜索“附近的用户”

Mongo 正则表达式查询嵌入对象列表中的字段

从嵌入式 RavenDB 中的索引检索结果时出现问题

SQL多表链接查询、嵌入SELECT语句的子查询技术