假设我们需要在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运行此类查询?
答案 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 } },
...
)