如何根据第一个或最后一个嵌入文档中的字段值提取Mongoid文档?

时间:2013-05-10 21:15:47

标签: ruby mongodb mongoid

我希望根据上一个嵌入式Order文档中的字段找到Notification个文档。

在下面的示例中,我希望找到包含一个或多个嵌入式pending的所有orders notifications,以及最后一个notificationdatetime的位置这是5到10天之间。

我的建议似乎没有做到这一点......:

Order.where(status: 'pending').gte('notifications.last.datetime' => 5.days.ago).lte('notifications.last.datetime' => 10.days.ago)

以下是两种模式:

class Order
  include Mongoid::Document
  field :datetime, type: DateTime
  field :status, type: String, default: 'pending'
  embeds_many :notifications,  :inverse_of => :order
end

class Notification
  include Mongoid::Document
  field :datetime, type: DateTime
  embedded_in :order, :inverse_of => :notifications
end

2 个答案:

答案 0 :(得分:2)

问题的主要问题似乎是如何在查询中引用数组的LAST元素。

不幸的是,从MongoDB 2.4开始是不可能的。 实现此功能的最简单方法是使用负值指向数组中的元素,如'notifications.-1.datetime',但它不起作用。 (请参阅[#SERVER-5565] Handle negative array offsets consistently - MongoDB。)

更糟糕的是,使用聚合框架解决这个问题似乎也是不可能的。没有办法 在$unwind ing([#SERVER-4588] aggregation: add option to $unwind to emit array index - MongoDB)或时,为每个元素添加数组索引 $project时动态选择数组的索引。 ([#SERVER-4589] aggregation: need an array indexing operator - MongoDB

因此,您唯一的选择似乎是更改架构以匹配您想要的。最简单的方法是向Order个字段添加一个包含最后datetime Notification的字段。

<强>更新

您可以先从服务器获取所有候选人,然后在客户端缩小它们以获得最终结果集。这不涉及架构更改。如果数据库规模相对较小或性能下降可以接受,这可能是最好的解决方案。

query = Order.where(status: 'pending').elem_match(
  notifications: { datetime: { '$gte' => 10.days.ago, '$lte' => 5.days.ago } })
query.select do |order|
  # datetime = order.notifications[0].datetime
  datetime = order.notifications[order.notifications.size - 1].datetime
  10.days.ago <= datetime && datetime <= 5.days.ago
end.each do |order|
  p order # result
end

答案 1 :(得分:0)

我知道它来得有点晚了,但是嘿,比从来没有好过。 :P

您可以在以下位置使用JavaScript:

Order.where("this.notifications[this.notifications.length - 1].datetime > new Date('#{5.days.ago}')")

刚刚发现这一点,并且在不改变模型的情况下是一个巨大的解脱。希望有所帮助!