mongodb MongoDB按字段聚合存在
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25497150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MongoDB aggregate by field exists
提问by Erik Buchanan
I have a hard time believing this question hasn't been asked and answered somewhere already, but I can't find any trace of it.
我很难相信这个问题还没有在某个地方被问过和回答过,但我找不到任何痕迹。
I have a MongoDB aggregation query that needs to group by a boolean: the existence of another field.
我有一个需要按布尔值分组的 MongoDB 聚合查询:另一个字段的存在。
For example let's start with this collection:
例如,让我们从这个集合开始:
> 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 documents have "field", and 2 don't. Note that each value of "field" may be different; we just want to group on its existence (or non-nullness works for me too, I don't have any null values stored).
2 个文件有“字段”,2 个没有。请注意,“字段”的每个值可能不同;我们只想对其存在进行分组(或者非空性也适用于我,我没有存储任何空值)。
I've tried using $project, but $exists doesn't exist there, and $cond and $ifNull haven't helped me. The field always appears to exist, even when it doesn't:
我试过使用 $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 }
I would expect the following much simpler aggregate to work, but for some reason $exists isn't supported in this way:
我希望以下更简单的聚合可以工作,但由于某种原因 $exists 不支持这种方式:
> 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
Does anyone know how to get the desired result from a collection like this?
有谁知道如何从这样的集合中获得所需的结果?
Expected result:
预期结果:
{ "_id" : true, "count" : 2 }
{ "_id" : false, "count" : 2 }
回答by kdkeck
I solved the same problem just last night, this way:
我昨晚解决了同样的问题,这样:
> db.test.aggregate({$group:{_id:{$gt:["$field", null]}, count:{$sum:1}}})
{ "_id" : true, "count" : 2 }
{ "_id" : false, "count" : 2 }
See http://docs.mongodb.org/manual/reference/bson-types/#bson-types-comparison-orderfor a full explanation of how this works.
有关其工作原理的完整说明,请参阅http://docs.mongodb.org/manual/reference/bson-types/#bson-types-comparison-order。
回答by Delcon
I solved it with checking for undefined
我通过检查未定义来解决它
$ne : [$var_to_check, undefined]
or
或者
$ne: [ { $type : "$var_to_check"}, 'missing'] }
This returns true if the var is defined
如果定义了 var,则返回 true
回答by Neil Lunn
The $exists
operator is a "query" operator, so it is used basically to "filter" results rather than identify a logical condition.
所述$exists
操作员是一个“查询”操作符,所以它基本上是用来“过滤器”的结果,而不是确定的逻辑条件。
As a "logical" operator the aggregation framework supports the $ifNull
operator. This returns the field value where it exists or the alternate supplied value where it does not or otherwise evaluates to null
作为“逻辑”运算符,聚合框架支持$ifNull
运算符。这将返回它存在的字段值或它不存在或以其他方式评估为的替代提供的值null
db.test.aggregate([
{ "$group": {
"_id": { "$ifNull": [ "$field", false ] },
"count": { "$sum": 1 }
}}
])
But of course, even that is not a "true/false" comparison, so unless you actually want to return the actual value of the field where it is present, then you are probably better off with a $cond
statement much like you have:
但是当然,即使这也不是“真/假”比较,因此除非您确实想返回它所在字段的实际值,否则您可能最好使用如下$cond
语句:
db.test.aggregate([
{ "$group": {
"_id": { "$cond": [{ "$eq": [ "$field", null ] }, true, false ] },
"count": { "$sum": 1 }
}}
])
Where $ifNull
can be very useful is in replacing not existent array fields that would otherwise cause an error using $unwind
. You can then do something like return a single element or empty array so this does not cause problems in the rest of your pipeline processing.
凡$ifNull
在更换会使用,否则会导致错误不存在的数组字段可以是非常有用的$unwind
。然后,您可以执行诸如返回单个元素或空数组之类的操作,这样就不会在管道处理的其余部分中造成问题。
回答by djuleAyo
Dunno how it was but now in 2019 there is clean solution. In aggregation pipeline do this
不知道它是怎么回事,但现在在 2019 年有干净的解决方案。在聚合管道中执行此操作
$match: {"my_field": {$ne: null}}
Nice thing is in my lang 'ne' means not :)
好东西在我的语言中 'ne' 意味着不是 :)
回答by egvo
My answer is:
我的回答是:
{'$project': {
'field_exists': {'$or': [
{'$eq': ['$field', null]},
{'$gt': ['$field', null]},
]},
}}
Here are the details. $exists means that the field exists, even if it is null
or any other empty value. That is why all the answers on this page are incorrect.
这是详细信息。$exists 表示该字段存在,即使它是null
或任何其他空值。这就是为什么此页面上的所有答案都不正确的原因。
Let's test a bit. Check this:
让我们测试一下。检查这个:
// 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': {}},
}},
])
We'll get this:
我们会得到这个:
{
"null_field" : null,
"not_null_field" : {}
}
Then let's clarify which fields exist in this doc:
然后让我们澄清一下这个文档中存在哪些字段:
- null_field - exists
- not_null_field - exists
- non_existent_field - doesn't.
- null_field - 存在
- not_null_field - 存在
- non_existent_field - 没有。
Okay, it's time to test project stage I've mentioned above. Let's add it for every field we're interested in:
好的,是时候测试我上面提到的项目阶段了。让我们为我们感兴趣的每个领域添加它:
{'$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]},
]},
}},
What we get is:
我们得到的是:
{
"null_field_exists" : true,
"not_null_field_exists" : true,
"non_existent_field_exists" : false
}
Correct!
正确的!
And a small note: we use null
for comparing because it is the smallest value at least valuable (smaller is just the non-existence).
还有一个小提示:我们null
用于比较,因为它是最小的值,至少有价值(较小的只是不存在)。
回答by Blush_Wig Théo
My answer is:
我的回答是:
{$match:{
$and:[{
name:{
$exists:true
}
}, {
$expr:{
$eq:["$$id", "$_id"]
}
}]
}}
I use this in lookup, on my pipeline stage. This post 2 rules the first one, name must exist. And the second thing is the relation between these 2 collection. I Am sure u can modify this for your question.
我在查找中使用它,在我的管道阶段。这个帖子2规则第一个,名字必须存在。第二件事是这两个集合之间的关系。我相信你可以针对你的问题修改这个。