Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB aggregate by field exists

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.

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).

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:

> 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:

> 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 } 
like image 652
Erik Buchanan Avatar asked Aug 26 '14 02:08

Erik Buchanan


People also ask

How do you check if a field exist in MongoDB?

In MongoDB, we can check the existence of the field in the specified collection using the $exists operator. When the value of $exists operator is set to true, then this operator matches the document that contains the specified field(including the documents where the value of that field is null).

What does $match do in MongoDB?

The MongoDB $match operator filters the documents to pass only those documents that match the specified condition(s) to the next pipeline stage.

Is aggregate faster than find MongoDB?

Because of this, if you have a simple aggregation pipeline or one which does not cut down the data volume much it can often be quicker to use a find() and perform the aggregation client side.


1 Answers

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-order for a full explanation of how this works.

like image 109
kdkeck Avatar answered Sep 17 '22 18:09

kdkeck