将布尔字段查询为“不正确”(例如,错误或不存在)
Posted
技术标签:
【中文标题】将布尔字段查询为“不正确”(例如,错误或不存在)【英文标题】:Query for boolean field as "not true" (e.g. either false or non existent) 【发布时间】:2013-09-21 03:53:06 【问题描述】:我确定我在 MongoDB 查询中遗漏了一些非常基本的东西,似乎无法得到这个简单的条件。
考虑这个系列
> db.tests.find()
"_id" : ObjectId("..."), "name" : "Test1" , "deleted" : true
"_id" : ObjectId("..."), "name" : "Test2" , "deleted" : false
"_id" : ObjectId("..."), "name" : "Test3"
我只想查询所有“未删除”的项目
我知道如何找到将“已删除”标志设置为 true 的项目:
> db.tests.find(deleted:true)
"_id" : ObjectId("..."), "name" : "Test1" , "deleted" : true
但是我如何找到所有不是"deleted"
的项目(例如否定上述查询,或者换句话说,任何没有"deleted"
字段或具有值false
的项目
我猜测的结果(请不要笑...)
> db.tests.find($not : deleted: true)
(不返回任何结果)
> db.tests.find($not : $eq:deleted:true)
error: "$err" : "无效操作符: $eq", "code" : 10068
> db.tests.find(deleted:$not: true)
error: "$err" : "$not 的使用无效", "code" : 13041
> db.tests.find(deleted:$not: $eq:true)
error: "$err" : "$not 的使用无效", "code" : 13034
我错过了什么?
【问题讨论】:
【参考方案1】:如果您正在寻找 mongoid 语法(我在 Rails 应用程序中使用它),这是我为公司用户想出的:
2.3.1 :042 > accepted_consent = org.users.active.where(:accepted_terms_and_conditions => true).count
=> 553
2.3.1 :043 > not_accepted_yet = org.users.active.where(:accepted_terms_and_conditions.ne => true).count
=> 6331
2.3.1 :044 > 6331+553
=> 6884
2.3.1 :045 > org.users.active.count
=> 6884
【讨论】:
【参考方案2】:如果有人在聚合管道中需要它而不是 find
,这对我有用
db.getCollection('tests').aggregate([
// ...previous operations...
$addFields: "deleted_conclusion": $cond:
if: $ne: [ "$deleted", false ], then: $cond: [ "$deleted", ":TRUE", ":FALSY"], else: ":FALSE"
])
添加额外字段后,您可以继续流水线阶段并获取您错过的信息
【讨论】:
【参考方案3】:JohnnyHK 给出了最好的答案。 $in
选择器是最短和最干净的 IMO。
这将完全测试“假”或“不存在”。并且可以被索引。
db.tests.find($or:[deleted:false,deleted:$exists:false])
一个使用索引的例子。
((function()
print("creating collection 'testx' and inserting 50 trues, 50 falses, 50 non-existents");
db.testx.drop();
db.testx.ensureIndex(deleted:1);
for (var i=0;i<50;i++)
db.testx.insert(i:i,deleted:false);
;
for (var i=0;i<50;i++)
db.testx.insert(i:i,deleted:true);
;
for (var i=0;i<50;i++)
db.testx.insert(i:i);
;
var res0 = db.testx.find().explain();
var res1 = db.testx.find(deleted:false).explain();
var res2 = db.testx.find(deleted:true).explain();
var res3 = db.testx.find(deleted:$exists:false).explain();
var res4 = db.testx.find($or:[deleted:false,deleted:$exists:false]).explain();
var res5 = db.testx.find($or:[deleted:true,deleted:$exists:false]).explain();
var res6 = db.testx.find(deleted:$in:[false,null]).explain();
print("res0: all objects ("+res0["n"]+" found, "+res0["nscannedObjects"]+" scanned)");
print("res1: deleted is false ("+res1["n"]+" found, "+res1["nscannedObjects"]+" scanned)");
print("res2: deleted is true ("+res2["n"]+" found, "+res2["nscannedObjects"]+" scanned)");
print("res3: deleted is non-existent ("+res3["n"]+" found, "+res3["nscannedObjects"]+" scanned)");
print("res4: deleted is false or non-existent ("+res4["n"]+" found, "+res4["nscannedObjects"]+" scanned)");
print("res5: deleted is true or non-existent ("+res5["n"]+" found, "+res5["nscannedObjects"]+" scanned)");
print("res6: deleted is in [false,null] ("+res5["n"]+" found, "+res5["nscannedObjects"]+" scanned)");
)())
这应该打印出来
creating collection 'testx' and inserting 50 trues, 50 falses, 50 non-existents
res0: all objects (150 found, 150 scanned)
res1: deleted is false (50 found, 50 scanned)
res2: deleted is true (50 found, 50 scanned)
res3: deleted is non-existent (50 found, 50 scanned)
res4: deleted is false or non-existent (100 found, 100 scanned)
res5: deleted is true or non-existent (100 found, 100 scanned)
res6: deleted is in [false,null] (100 found, 100 scanned)
【讨论】:
当我对此查询进行解释时,它显示索引仅用于查询的“已删除:假”部分。 'deleted:$exists:false' 似乎没有使用索引。 @emilebaizel $exists 应该可用于索引。 Mongo jira.mongodb.org/browse/SERVER-10608 啊哈!大概就是这样。我们在 2.4。【参考方案4】:为了完整起见,另一种方法是使用$in
:
db.test.find(deleted: $in: [null, false])
在数组中包含null
会拉入缺少deleted
字段的文档。此查询可以在当前 2.6.6 MongoDB 版本中使用deleted: 1
上的索引。
【讨论】:
【参考方案5】:db.tests.find(deleted: $ne: true)
$ne
代表“不等于”。 (Documentation on mongodb operators)
【讨论】:
根据文档,使用 $ne 似乎没有利用索引 - 是否有另一种能够利用索引的解决方案? docs.mongodb.org/manual/faq/indexes/… 只是为其他读者重新迭代 - 此查询不会使用索引。所以请不要在生产中使用。 那么在生产中应该使用什么来代替? @Juhana 我刚刚用 MongoDB 2.6.6 测试了它,它确实现在使用为deleted: 1
创建的索引。
在 3.6.8 下使用复合索引未正确索引,但 $in: [false,null]
似乎有效。以上是关于将布尔字段查询为“不正确”(例如,错误或不存在)的主要内容,如果未能解决你的问题,请参考以下文章
AWS 环境中的 WCF UserNameTransport 错误 - 收到不安全或不正确安全的故障