8

I have a collection in a MongoDB that contains a field "events" which is an array. I need to write an aggregate query for this that checks for the events array to not be empty, but can't find a way to do this.

I want something like:

db.collection.aggregate([
    { 
        $match: { 
            events: {
                "$empty": false 
            }
        }
    }
]);

2 Answers 2

18

After some digging around and having tried several options (including a nasty project of $gte: 0 of the $size followed by a match on that projected field) I eventually found the following makes sense and actually works:

db.collection.aggregate([
    { 
        $match: { 
            "events.0": {
                "$exists": true 
            }
        }
    }
]);
Sign up to request clarification or add additional context in comments.

Comments

2

Query

  • match to test if not-equal with the empty array
    ($size costs O(n) as far as i know so its bad way to check this)

Test code here

*this query looks straight forward way to do it(yours looks more tricky), but i dont know which is faster, if you benchmark it or anyone knows add on comments if you can

aggregate([{"$match":{"$expr":{"$ne":["$events", []]}}}])

If you want to the document to pass, if its other type of array, you can do this.

aggregate(
[{"$match":
  {"$expr":
   {"$cond":
    [{"$isArray":["$events"]}, {"$ne":["$events", []]}, true]}}}]
)

Your solution is fine if you only want to do this and maybe faster, but if you need an aggregation way to do it, you can use this. For example to check if empty outside of a $match.

2 Comments

While this certainly manages to return all events that have at least one event in the array, it also finds documents that have an events value that is not an array. For example when the value would be a String. While this would be an unlikely scenario, this is possible in MongoDB.
this is fixable, by adding one more check, i guess you can use any way, i havent benchmarked them to tell you what is faster, i will test it sometime.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.