我确定我在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}}})
错误:{“$ err”:“运营商无效:$ eq”,“代码”:10068}
> db.tests.find({deleted:{$not: true}})
错误:{“$ err”:“无效使用$ not”,“代码”:13041}
> db.tests.find({deleted:{$not: {$eq:true}}})
错误:{“$ err”:“无效使用$ not”,“代码”:13034}
我错过了什么?
答案 0 :(得分:114)
db.tests.find({deleted: {$ne: true}})
$ne
代表“不相等”。 (Documentation on mongodb operators)
答案 1 :(得分:25)
为了完整起见,另一种方法是使用$in
:
db.test.find({deleted: {$in: [null, false]}})
在数组中加入null
会拉入缺少deleted
字段的文档。此查询可以在当前2.6.6 MongoDB版本中使用{deleted: 1}
上的索引。
答案 2 :(得分:6)
JohnnyHK有最好的答案。 $in
选择器是最短,最干净的IMO。
这将完全测试" false"或者"不存在"。并且可以编入索引。
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)
答案 3 :(得分:0)
对于有人在聚合管道中而不是find
需要此情况的情况,这对我有用
db.getCollection('tests').aggregate([
// ...previous operations...
{ $addFields: { "deleted_conclusion": { $cond: {
if:{ $ne: [ "$deleted", false ]}, then: { $cond: [ "$deleted", ":TRUE", ":FALSY"]}, else: ":FALSE"
}}}}
])
添加额外字段后,您可以继续使用管道阶段并获取您错过的信息
答案 4 :(得分:0)
如果您正在寻找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