mongoid:Rails 表示字段存在,mongodb 表示相反
mongoid: Rails says field exists, mongodb says contrary
我收集了一些复杂的文档。
{
<some fields>,
meta_info: {
company_name: String,
invalid: Boolean,
mobile_layout: String,
<more fields>
}
<lots more fields>
}
我要求 Rails 使用
找到 meta_info.invalid
为 true/false/nil 的所有文档
finished_acts.where('meta_info.invalid' => true/false/nil)
现在有一个文档的字段不存在。我问...
finished_acts.find('meta_info.invalid' => {'$exists' => false})
=> nil
这是不正确的(如果我问 {'$exists' => true}
,它也会产生 nil),
也是如此
finished_acts.where('meta_info.invalid' => {'$exists' => false}).count
=> 0
如何找到这份文件?我花了好几天时间收集统计数据,与数据库本身给我的信息相比,这些数据总是差一个计数,这个不存在的字段就是原因。
我正在使用 mongoDB V3.4.17 和 Mongoid 6.1.0。
编辑:从那以后我了解到我错误地使用了 .find
命令,它仅用于 _id
字段并且不接受 JSON/Hashes。
我的问题显然显示了 Mongoid 的 Active Record 适配实现中的错误,我正在慢慢转换我的代码以始终使用聚合。这样做时,我得到了正确数量的文档。当然,聚合返回的结构处理起来更复杂,因为它只是散列和数组,但如果这是获得正确结果的权衡,我很高兴。
不要依赖 Mongoid 中的 ActiveRecord 适配;使用聚合管道。这将(据我所知)总是 return 正确的结果,因为它只是将参数哈希推入 mongo.
聚合管道乍一看似乎使用起来不直观,但在您了解如何使用它之后,如果您想进行复杂的查询,它是一个非常强大的工具。 Rails语法如下:
MyClassName.collection.aggregate( <array> )
其中<array>
包含散列,每个散列都是对前面散列的执行结果使用的命令。可以在 https://docs.mongodb.com/manual/aggregation/ 找到文档。
要将那里的命令转换为 Ruby,只需要用引号将条目括起来。
举个例子:下面是mongo语法:
db.orders.aggregate([
{ $match: { status: "A" } },
{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])
这会从 orders
集合中获取所有文档,并选择所有状态字段匹配“A”的文档(冒号左边的单词 $match
是一个 mongo 命令) .然后根据 cust_id
字段对这些进行分组 ($group
),并计算 amount
字段内容的总和 ($sum
)。
如果要将其转换为Ruby,则将其更改为
Orders.collection.aggregate([
{ '$match': {'status': 'A'}},
{ '$group': {'_id': '$cust_id', 'total': {'$sum': '$amount'}}}
])
这对我有用,更好的是它比在 Rails 和 Orders.where(...) 中使用 Orders.where(...)在 Rails 中进行计算。
权衡是你没有得到 returned Ruby 对象,而是散列数组的散列。
我收集了一些复杂的文档。
{
<some fields>,
meta_info: {
company_name: String,
invalid: Boolean,
mobile_layout: String,
<more fields>
}
<lots more fields>
}
我要求 Rails 使用
找到meta_info.invalid
为 true/false/nil 的所有文档
finished_acts.where('meta_info.invalid' => true/false/nil)
现在有一个文档的字段不存在。我问...
finished_acts.find('meta_info.invalid' => {'$exists' => false})
=> nil
这是不正确的(如果我问 {'$exists' => true}
,它也会产生 nil),
finished_acts.where('meta_info.invalid' => {'$exists' => false}).count
=> 0
如何找到这份文件?我花了好几天时间收集统计数据,与数据库本身给我的信息相比,这些数据总是差一个计数,这个不存在的字段就是原因。
我正在使用 mongoDB V3.4.17 和 Mongoid 6.1.0。
编辑:从那以后我了解到我错误地使用了 .find
命令,它仅用于 _id
字段并且不接受 JSON/Hashes。
我的问题显然显示了 Mongoid 的 Active Record 适配实现中的错误,我正在慢慢转换我的代码以始终使用聚合。这样做时,我得到了正确数量的文档。当然,聚合返回的结构处理起来更复杂,因为它只是散列和数组,但如果这是获得正确结果的权衡,我很高兴。
不要依赖 Mongoid 中的 ActiveRecord 适配;使用聚合管道。这将(据我所知)总是 return 正确的结果,因为它只是将参数哈希推入 mongo.
聚合管道乍一看似乎使用起来不直观,但在您了解如何使用它之后,如果您想进行复杂的查询,它是一个非常强大的工具。 Rails语法如下:
MyClassName.collection.aggregate( <array> )
其中<array>
包含散列,每个散列都是对前面散列的执行结果使用的命令。可以在 https://docs.mongodb.com/manual/aggregation/ 找到文档。
要将那里的命令转换为 Ruby,只需要用引号将条目括起来。
举个例子:下面是mongo语法:
db.orders.aggregate([
{ $match: { status: "A" } },
{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])
这会从 orders
集合中获取所有文档,并选择所有状态字段匹配“A”的文档(冒号左边的单词 $match
是一个 mongo 命令) .然后根据 cust_id
字段对这些进行分组 ($group
),并计算 amount
字段内容的总和 ($sum
)。
如果要将其转换为Ruby,则将其更改为
Orders.collection.aggregate([
{ '$match': {'status': 'A'}},
{ '$group': {'_id': '$cust_id', 'total': {'$sum': '$amount'}}}
])
这对我有用,更好的是它比在 Rails 和 Orders.where(...) 中使用 Orders.where(...)在 Rails 中进行计算。 权衡是你没有得到 returned Ruby 对象,而是散列数组的散列。