运行 范围查询的 Mongoid 语法

Mongoid Syntax for running range queries with or condition

假设我们需要在 Mongoid 中编写一个范围查询。设要查询的字段为range_field,那么我们做这样的事情

where(:range_field.lte => some-date-time, :range_field.gte => some-date-time)

但是如果我想运行一个查询来选择多个范围中的任何一个,我必须这样做

.or({:range_field.lte => some-date-time1, :range_field.gte => some-date-time2},{:range_field.lte => some-date-time3, :range_field.gte => some-date-time4})

这显然行不通。 我如何 运行 使用 Mongoid 进行此类查询?

当你说:

:range_field.lte => some_date_time

你正在调用一个方法,lte,Mongoid mongoid monkey patches in Symbol。该方法 returns 一个 Origin::Key 实例,包裹在底层 $lte 运算符周围。在 Mongoid 内部的某个地方,Origin::Key 将被转换为 MongoDB 能够理解的东西:

{ range_field: { $lte: some_date_time } }

如果你看什么

where(:range_field.lte => t1, :range_field.gte => t2)

通过对结果调用 selector 变成,你会看到这样的东西:

{
  "created_at" => {
    :$gte => t2,
    :$lte => t1
  }
}

一切都会正常进行。

但是,如果我们使用 #or 并调用 selector 来查看底层查询,我们会看到 Mongoid 正在一个接一个地展开 Origin::Key 并合并结果:

or({:range_field.lte => t1, :range_field.gte => t2})
# is expanded as though as you said
or({ :range_field => { :$lte => t1 }, :range_field => { :$gte => t2 } })
# which is the same as
or({ :range_field => { :$gte => t2 } })

本质上,Mongoid 在如何扩展 Origin::Key 方面是不一致的。如果您使用 :$or 而不是 #or:

,您甚至会得到同样令人困惑的结果
where(:$or => [ {:range_field.lte => t1, :range_field.gte => t2} ]).selector

会说:

{ "$or" => [ { "range_field" => { "$gte" => t2 } } ] }

解决方案是不使用 Symbol 猴子修补方法并手动完成该部分:

or(
  { :range_field => { :$lte => t1, :$gte => t2 } },
  { :range_field => { :$lte => t3, :$gte => t4 } }, 
  ...
)