我很难相信这个问题已经在某个地方被问过并回答了,但是我无法找到它的任何痕迹。
我有一个需要按布尔值分组的MongoDB聚合查询:是否存在另一个字段。
例如,让我们从这个集合开始:
> db.test.find()
{ "_id" : ObjectId("53fbede62827b89e4f86c12e"),
"field" : ObjectId("53fbede62827b89e4f86c12d"), "name" : "Erik" }
{ "_id" : ObjectId("53fbee002827b89e4f86c12f"), "name" : "Erik" }
{ "_id" : ObjectId("53fbee092827b89e4f86c131"),
"field" : ObjectId("53fbee092827b89e4f86c130"), "name" : "John" }
{ "_id" : ObjectId("53fbee122827b89e4f86c132"), "name" : "Ben" }
2个文件有"字段",2不要。 注意" field"的每个值。可能会有所不同;我们只是想对它的存在进行分组(或者非null也适用于我,我也没有存储任何空值)。
我已经尝试过使用$ project,但$ exists并不存在,$ cond和$ ifNull还没有帮助我。该字段似乎总是存在,即使它没有:
> db.test.aggregate(
{$project:{fieldExists:{$cond:[{$eq:["$field", null]}, false, true]}}},
{$group:{_id:"$fieldExists", count:{$sum:1}}}
)
{ "_id" : true, "count" : 4 }
我希望以下更简单的聚合工作,但由于某种原因,$以这种方式不支持:
> db.test.aggregate({$group:{_id:{$exists:"$field"}, count:{$sum:1}}})
assert: command failed: {
"errmsg" : "exception: invalid operator '$exists'",
"code" : 15999,
"ok" : 0
} : aggregate failed
Error: command failed: {
"errmsg" : "exception: invalid operator '$exists'",
"code" : 15999,
"ok" : 0
} : aggregate failed
at Error (<anonymous>)
at doassert (src/mongo/shell/assert.js:11:14)
at Function.assert.commandWorked (src/mongo/shell/assert.js:244:5)
at DBCollection.aggregate (src/mongo/shell/collection.js:1149:12)
at (shell):1:9
2014-08-25T19:19:42.344-0700 Error: command failed: {
"errmsg" : "exception: invalid operator '$exists'",
"code" : 15999,
"ok" : 0
} : aggregate failed at src/mongo/shell/assert.js:13
有谁知道如何从这样的集合中获得所需的结果?
预期结果:
{ "_id" : true, "count" : 2 }
{ "_id" : false, "count" : 2 }
答案 0 :(得分:60)
我昨晚解决了同样的问题,这样:
> db.test.aggregate({$group:{_id:{$gt:["$field", null]}, count:{$sum:1}}})
{ "_id" : true, "count" : 2 }
{ "_id" : false, "count" : 2 }
请参阅http://docs.mongodb.org/manual/reference/bson-types/#bson-types-comparison-order以获取有关其工作原理的完整说明。
答案 1 :(得分:8)
我通过检查未定义的
解决了这个问题$ne : [$var_to_check, undefined]
或
$ne: [ { $type : "$var_to_check"}, 'missing'] }
如果定义了var
,则返回true答案 2 :(得分:7)
$exists
运算符是&#34;查询&#34;运算符,因此它基本上用于&#34; filter&#34;结果而不是确定一个逻辑条件。
作为一个&#34;逻辑&#34;运算符聚合框架支持$ifNull
运算符。这将返回其存在的字段值或其未提供的备用提供值,或以其他方式计算为null
db.test.aggregate([
{ "$group": {
"_id": { "$ifNull": [ "$field", false ] },
"count": { "$sum": 1 }
}}
])
但当然,即使这不是&#34;真/假&#34;比较,所以除非你真的想要返回它所在的字段的实际值,那么你最好使用$cond
语句,就像你一样:
db.test.aggregate([
{ "$group": {
"_id": { "$cond": [{ "$eq": [ "$field", null ] }, true, false ] },
"count": { "$sum": 1 }
}}
])
$ifNull
非常有用的地方在于替换不存在的数组字段,否则会导致使用 $unwind
导致错误。然后,您可以执行返回单个元素或空数组的操作,这样就不会在管道处理的其余部分中引起问题。
答案 3 :(得分:2)
我通过使用 $addFields 和 $ifNull 解决了这个问题,然后通过检查其值是否为空来$match 添加的字段。
collection.aggregate(
[
{
$addFields:{
fieldName:{
$ifNull:["$fieldToCheckIfExists", null]
}
}
},
{
$match:{
fieldName:{
$ne: null
}
}
]
答案 4 :(得分:1)
唐诺(Dunno)过去的情况,但现在在2019年有了干净的解决方案。在聚合管道中执行此操作
$match: {"my_field": {$ne: null}}
在我的语言中,“ ne”的意思不是:)
答案 5 :(得分:1)
我的答案是:
{$match:{
$and:[{
name:{
$exists:true
}
}, {
$expr:{
$eq:["$$id", "$_id"]
}
}]
}}
我在管道阶段在查找中使用它。 此帖子2规则第一个,名称必须存在。第二件事是这两个集合之间的关系。 我确定您可以针对您的问题对此进行修改。
答案 6 :(得分:1)
只在猫鼬中工作
$ne: [ { $type : "$var_to_check"}, 'missing'] }
答案 7 :(得分:0)
我的答案是:
{'$project': {
'field_exists': {'$or': [
{'$eq': ['$field', null]},
{'$gt': ['$field', null]},
]},
}}
这是详细信息。 $ exists表示该字段存在,即使它是null
或任何其他空值。因此,此页面上的所有答案都不正确。
让我们测试一下。检查一下:
// Let's take any collection that have docs
db.getCollection('collection').aggregate([
// Get arbitrary doc, no matter which, we won't use it
{"$limit": 1},
// Project our own fields (just create them with $literal)
{'$project': {
'_id': 0,
'null_field': {'$literal': null},
'not_null_field': {'$literal': {}},
}},
])
我们会得到这个:
{
"null_field" : null,
"not_null_field" : {}
}
然后让我们澄清一下该文档中存在哪些字段:
好的,该测试我上面提到的项目阶段了。让我们将其添加到我们感兴趣的每个领域:
{'$project': {
'null_field_exists': {'$or': [
{'$eq': ['$null_field', null]},
{'$gt': ['$null_field', null]},
]},
'not_null_field_exists': {'$or': [
{'$eq': ['$not_null_field', null]},
{'$gt': ['$not_null_field', null]},
]},
'non_existent_field_exists': {'$or': [
{'$eq': ['$non_existent_field', null]},
{'$gt': ['$non_existent_field', null]},
]},
}},
我们得到的是:
{
"null_field_exists" : true,
"not_null_field_exists" : true,
"non_existent_field_exists" : false
}
正确!
还有一个小注释:我们使用null
进行比较,因为它是至少有价值的最小值(较小的值就是不存在的值)。
答案 8 :(得分:0)
一种语义透明的解决方案,用于检查字段是否存在且不为空:
{ $ne: [{ $ifNull: ["$field", null] }, null] }
要检查它是否丢失,请将 $ne
替换为 $eq
。