MongoDB aggregate by field exists

前端 未结 6 1425
不思量自难忘°
不思量自难忘° 2020-12-02 12:33

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 t

相关标签:
6条回答
  • 2020-12-02 12:33

    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.

    0 讨论(0)
  • 2020-12-02 12:35

    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

    0 讨论(0)
  • 2020-12-02 12:36

    In short

    {'$project': {
        'field_exists': {'$or': [
            {'$eq': ['$field', null]}, 
            {'$gt': ['$field', null]},
        ]},
    }}
    

    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.

    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:

    1. null_field - exists
    2. not_null_field - exists
    3. non_existent_field - doesn't.

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

    0 讨论(0)
  • 2020-12-02 12:56

    Dunno how it was but now in 2019 there is clean solution. In aggregation pipeline do this

    $match: {"my_field": {$ne: null}}
    

    Nice thing is in my lang 'ne' means not :)

    0 讨论(0)
  • 2020-12-02 12:57

    The $exists operator is a "query" operator, so it is used basically to "filter" results rather than identify a logical condition.

    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

    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:

    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.

    0 讨论(0)
  • 2020-12-02 12:59

    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.

    0 讨论(0)
提交回复
热议问题