使用或条件运行范围查询的Mongoid语法

时间:2016-06-07 20:20:51

标签: ruby-on-rails ruby mongodb mongoid

假设我们需要在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运行此类查询?

1 个答案:

答案 0 :(得分:1)

当你说:

:range_field.lte => some_date_time

你正在调用lte中的Mongoid猴子补丁方法Symbol。该方法返回一个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 } }, 
  ...
)