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



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

在下面的示例中,我希望找到具有一个或多个嵌入的notifications的所有pending orders,并且其中最后一个notification具有在5到10天之间的datetime

我的建议似乎没有奏效…:

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

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

不幸的是,从MongoDB 2.4开始,这是不可能的。实现此特性的最简单方法是使用负值来指向像'notifications.-1.datetime'这样的数组中的元素,但它不起作用。(参考[#SERVER-5565]一致处理负数组偏移-MongoDB。(

更糟糕的是,使用聚合框架似乎也不可能解决这个问题。没有办法当$unwinding时,为每个元素添加一个数组索引([#SERVER-4588]aggregation:add option to$unvent to emission array index-MongoDB(或在$projecting时动态选择数组的索引。([#SERVER-4589]聚合:需要一个数组索引运算符-MongoDB(

因此,您唯一的选择似乎是更改模式以匹配您想要的内容。最简单的方法是向Order再添加一个字段,该字段包含最后一个Notificationdatetime

更新:

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

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

我知道它来得有点晚,但嘿,晚总比不晚好。:P

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

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

我刚刚发现了这一点,不用换我的模型,这让我松了一口气。希望能有所帮助!

最新更新