查询布尔字段为“不正确”(例如,错误或不存在)


77

我确定我在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”,“ code”:13041}

> db.tests.find({deleted:{$not: {$eq:true}}})

错误:{“ $ err”:“无效使用$ not”,“ code”:13034}

我想念什么?

Answers:


147
db.tests.find({deleted: {$ne: true}})

$ne代表“不平等”。(有关mongodb运算符的文档


2
根据文档,使用$ ne似乎没有利用索引-是否存在另一种可以利用索引的解决方案?docs.mongodb.org/manual/faq/indexes/...
joelsand

2
只是为其他读者重申-此查询将不使用index。所以请不要在生产中使用。
2014年

那么在生产中应该使用什么呢?
JJJ 2015年

9
@Juhana我刚刚在MongoDB 2.6.6上进行了测试,它现在确实使用为创建的索引{deleted: 1}
JohnnyHK

2
在3.6.8下没有使用复合索引正确地建立索引,但是$in: [false,null]似乎可以正常工作。
jimrandomh

31

为了完整起见,另一种方法是$in

db.test.find({deleted: {$in: [null, false]}})

包含null在数组中的文档会在deleted缺少该字段的文档中进行提取。该查询可以{deleted: 1}在当前2.6.6 MongoDB版本中使用索引on 。


6

强尼香港是最好的答案。在$in选择最短,最干净的海事组织。

这将测试准确的“假”或“不存在”。并且可以索引。

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:false”部分。'deleted:{$ exists:false}'似乎没有使用索引。
emilebaizel

@emilebaizel $ exists应该可以用于索引。Mongo <2.5.5的旧版本可能没有该功能。jira.mongodb.org/browse/SERVER-10608
tidwall

啊哈!就是这样。我们在2.4。
emilebaizel

1

对于有人需要在聚合管道中而不是的情况find,这对我有用

db.getCollection('tests').aggregate([ 
  // ...previous operations...
  { $addFields: { "deleted_conclusion": { $cond: {
        if:{ $ne: [ "$deleted", false ]}, then: { $cond: [ "$deleted", ":TRUE", ":FALSY"]}, else: ":FALSE"
  }}}}
])

添加了额外的字段后,您可以继续进行管道阶段并获得您错过的信息


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 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.