Mongoid:基于嵌入式文档数组的大小查询

时间:2014-08-28 00:08:43

标签: ruby mongodb mongodb-query mongoid

这与此问题类似,但我无法弄清楚如何将其转换为Mongoid语法:

MongoDB query based on count of embedded document

假设我有Customer: {_id: ..., orders: [...]}

我希望能够找到所有拥有现有订单的客户,即orders.size>我试过像Customer.where(:orders.size.gt => 0)这样的查询无济于事。是否可以使用exists?运算符完成?

2 个答案:

答案 0 :(得分:7)

我更好的方法是使用MongoDB的本机语法,而不是像你所链接的问题的接受答案中指出的方法或JavaScript评估那样使用rails。特别是评估JavaScript条件会慢得多。

对于长度大于零的数组,$exists的逻辑扩展名是使用"dot notation"并测试是否存在“零索引”或数组的第一个元素:

Customer.collection.find({ "orders.0" => { "$exists" => true } })

似乎可以使用任何索引值来完成,其中n-1等于您正在测试的数组的“长度”的索引值。

值得注意的是,对于“零长度”数组排除,当$size$not一起使用时,{{3}}运算符也是一种有效的替代方法:

Customer.collection.find({ "orders" => { "$not" => { "$size" => 0 } } })

但这并不适用于较大的“尺寸”测试,因为您需要指定要排除的所有尺寸:

Customer.collection.find({ 
    "$and" => [ 
        { "orders" => { "$not" => { "$size" => 4 } } }, 
        { "orders" => { "$not" => { "$size" => 3 } } },
        { "orders" => { "$not" => { "$size" => 2 } } },
        { "orders" => { "$not" => { "$size" => 1 } } },
        { "orders" => { "$not" => { "$size" => 0 } } }
    ]
})

所以其他语法更清晰:

Customer.collection.find({ "orders.4" => { "$exists" => true } })

这意味着5个或更多成员的简洁方式。

请注意,这些条件都不能只是一个索引,所以如果你有另一个过滤点,最好先包含那个条件。

答案 1 :(得分:5)

只需添加可能对某人有帮助的解决方案:

scope :with_orders, -> { where(orders: {"$exists" => true}, :orders.not => {"$size" => 0}}) }