在Mongo中如何查询“不为空”?

675

我想执行以下查询:

db.mycollection.find(HAS IMAGE URL)

应该使用什么正确的语法?


133
简短回答:查询 { field : {$ne : null} } 是用来检查非空值的。 http://docs.mongodb.org/manual/reference/operator/query/ne/ - Jaider
12个回答

1251

这将返回所有具有名为“IMAGE URL”的键的文档,但它们可能仍具有空值。

db.mycollection.find({"IMAGE URL":{$exists:true}});

这将返回所有具有名为“IMAGE URL”非空值的文档。

db.mycollection.find({"IMAGE URL":{$ne:null}});

根据文档,$exists目前无法使用索引,但$ne可以。

编辑:由于对此回答的关注,添加一些示例

给出以下插入:

db.test.insert({"num":1, "check":"check value"});
db.test.insert({"num":2, "check":null});
db.test.insert({"num":3});

这将返回所有三个文档:

db.test.find();

这将仅返回第一个和第二个文档:

db.test.find({"check":{$exists:true}});

这将只返回第一个文档:

db.test.find({"check":{$ne:null}});

这将只返回第二个和第三个文档:

db.test.find({"check":null})

21
根据文档,$ne 可以包含不包含该字段的文档。自您发布答案以来,这个情况有变化吗?http://docs.mongodb.org/manual/reference/operator/query/ne/ - Andrew Mao
6
我不相信那已经改变了。在检查$ne时,该值将在所有文档中进行检查,包括那些不包含该字段的文档,但是$ne:null仍然无法匹配不包含该字段的文档,因为该字段的值仍然为null,即使该字段在文档中不存在。 - Tim Gautier
2
你怎么只匹配第二个文档? - B T
3
@River 我在三年前写这篇文章时进行了检查,为了确保,我刚刚安装了Mongo并再次尝试了一下。它仍然以相同的方式工作,答案是正确的。倒数第二个查询仅返回第一个文档。 - Tim Gautier
2
给出的示例非常清楚地说明了如何使用它。 :-) - Eric Dela Cruz
显示剩余8条评论

155

一句话简介最好:

db.mycollection.find({ 'fieldname' : { $exists: true, $ne: null } });

在这里,

mycollection:填写您所需的集合名称

fieldname:填写您所需的字段名称

说明:

$exists:当 为true时,$exists匹配包含该字段的文档,包括字段值为null的文档。如果 为false,则查询仅返回不包含该字段的文档。

$ne:选择字段值与指定值不相等的文档,包括不包含该字段的文档。

因此,在您提供的情况下,以下查询将返回所有具有imageurl字段存在且值不为空的文档:

db.mycollection.find({ 'imageurl' : { $exists: true, $ne: null } });

26
$exists: true 是多余的, $ne: null 就足够了。 - Stanislav Karakhanov
1
这应该是最好的答案。$exists: true也会返回null值。必须同时使用$exists: true$ne: null。这不是冗余的。 - Ismail Kattakath
7
根据你自己的解释,$ne: null 使 $exists: true 生效!因为 $exists: true 返回 null 值,而 $ne: null 过滤掉这些值,所以你只需要使用 $ne: null - jessepinho

67
db.collection_name.find({"filed_name":{$exists:true}});

获取包含此字段名称的文档,即使它为null。

警告

db.collection_name.find({"filed_name":{$ne:null}});

获取字段值为$ne而不是null的文档,但该值也可以是空字符串。

我的建议:

db.collection_name.find({ "field_name":{$ne:null},$where:"this.field_name.length >0"})

59
在pymongo中,您可以使用:
db.mycollection.find({"IMAGE URL":{"$ne":None}});

因为 pymongo 把 mongo 的 null 表示为 python 的 None


这个答案只适用于Python。不正确。 - liberborn

20

分享给未来的读者。

以下是我们使用的查询语句(在MongoDB Compass中执行):

{
  "fieldName": {
    "$nin": [
      "",
      null
    ]
  }
}

1
{ $exists: true, $ne: null } 没有显示正确的结果。 您的查询运行良好。 - Oleksandr Buchek
3
注意,$nin 经常不会利用索引进行优化。 - Wheezil

12
在理想情况下,您希望测试所有三个值:null""空值(字段不存在于记录中)。您可以执行以下操作。
db.users.find({$and: [{"name" : {$nin: ["", null]}}, {"name" : {$exists: true}}]})

4
在Mongo Compass中检查列是否存在的最简单方法是:
{ 'column_name': { $exists: true } }

2
这个问题在于它假设该字段从未被持久化,但是根据 OP(原帖发布者)的标题所示,该字段可能存在但被显式地设置为 null。 - Carighan

3
db.<collectionName>.find({"IMAGE URL":{"$exists":"true"}, "IMAGE URL": {$ne: null}})

1
这是一个有效的Json文档吗?查询文档中有两个同名属性。如果必须在内存中构建它,不确定该如何实现。 - BrentR

3
一个未被提及的替代方案,但可能对某些人来说更有效(无法处理NULL条目)是使用稀疏索引(只有在字段中存在内容时才存在索引条目)。这是一个样本数据集:
db.foo.find()
{ "_id" : ObjectId("544540b31b5cf91c4893eb94"), "imageUrl" : "http://example.com/foo.jpg" }
{ "_id" : ObjectId("544540ba1b5cf91c4893eb95"), "imageUrl" : "http://example.com/bar.jpg" }
{ "_id" : ObjectId("544540c51b5cf91c4893eb96"), "imageUrl" : "http://example.com/foo.png" }
{ "_id" : ObjectId("544540c91b5cf91c4893eb97"), "imageUrl" : "http://example.com/bar.png" }
{ "_id" : ObjectId("544540ed1b5cf91c4893eb98"), "otherField" : 1 }
{ "_id" : ObjectId("544540f11b5cf91c4893eb99"), "otherField" : 2 }

现在,在imageUrl字段上创建稀疏索引:
db.foo.ensureIndex( { "imageUrl": 1 }, { sparse: true } )
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

现在,总是有可能(尤其是对于像我的样本这样的小数据集)MongoDB会使用表扫描,而不是使用索引,即使是潜在的涵盖索引查询。事实证明,这给了我一个很容易说明这里区别的方法:

db.foo.find({}, {_id : 0, imageUrl : 1})
{ "imageUrl" : "http://example.com/foo.jpg" }
{ "imageUrl" : "http://example.com/bar.jpg" }
{ "imageUrl" : "http://example.com/foo.png" }
{ "imageUrl" : "http://example.com/bar.png" }
{  }
{  }

好的,所以没有imageUrl的额外文档被返回了,只是空的,并不是我们想要的。为了确认原因,请执行以下操作:

db.foo.find({}, {_id : 0, imageUrl : 1}).explain()
{
    "cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 6,
    "nscannedObjects" : 6,
    "nscanned" : 6,
    "nscannedObjectsAllPlans" : 6,
    "nscannedAllPlans" : 6,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 0,
    "server" : "localhost:31100",
    "filterSet" : false
}

所以,是的,一个BasicCursor等同于对表进行全表扫描,它没有使用索引。让我们使用hint()强制查询使用我们的稀疏索引:

db.foo.find({}, {_id : 0, imageUrl : 1}).hint({imageUrl : 1})
{ "imageUrl" : "http://example.com/bar.jpg" }
{ "imageUrl" : "http://example.com/bar.png" }
{ "imageUrl" : "http://example.com/foo.jpg" }
{ "imageUrl" : "http://example.com/foo.png" }

这就是我们寻找的结果——只返回填充了字段的文档。这也仅使用索引(即它是一个覆盖索引查询),因此只需要将索引加载到内存中即可返回结果。
这是一个专门的用例,不能通常使用(请参见其他答案以获取这些选项)。特别要注意的是,目前你无法以这种方式使用count()(对于我的示例,它将返回6而不是4),因此请仅在适当时使用。

文本字段始终是稀疏索引,您不必明确指定。这只是我的个人意见。 - alianos-

2

您可以使用 $and 和 $exists 与 $nin 一起,以查找键的非空值的情况。

use dbname db.collectionname.find({$and : [{key : {$exists : true}},{$nin : [null,'',undefined]}]});

因为值可以存在或不存在。 对于这种情况,$exists 可用于检查该值。而对于值存在的情况下检查其详细信息,则使用 $nin 来排除 undefined、null 和空字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接