Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB aggregate return count of 0 if no results

Tags:

mongodb

I have the following MongoDB query that groups by date and result and gives a count. I'd like to have the query also return a count of 0 for a particular date and result if data doesn't exist for that day.

For example I have the following result statuses: SUCCESS and FAILED. If on the 21st there were no results of FAILED I would want a count returned of 0:

{
    "_id" : {
            "month" : 1,
            "day" : 21,
            "year" : 2014,
            "buildResult" : "FAILURE"
    },
    "count" : 0
}

I've done something similar with a relational database and a calendar table, but I'm not sure how to approach this with MongoDB. Is this possible or should I do something programatically after running the query?

Here is an example of a document (simplified) in the database:

    {
            "_id" : ObjectId("52deab2fe4b0a491abb54108"),
            "type" : "build",
            "time" : ISODate("2014-01-21T17:15:27.471Z"),
            "data" : {
                    "buildNumber" : 43,
                    "buildDuration" : 997308,
                    "buildResult" : "SUCCESS"
            }
    }

Here is my current query:

db.builds.aggregate([
    { $match: { "data.buildResult" : { $ne : null} }},
    { $group: { 
        _id: { 
            month: { $month: "$time" },
            day: { $dayOfMonth: "$time" },
            year: { $year: "$time" }, 
            buildResult: "$data.buildResult",
        },
        count: { $sum: 1}
    } },

    { $sort: { "_id.year": 1, "_id.month": 1, "_id.day": 1} }
])
like image 602
JamesE Avatar asked Feb 21 '14 15:02

JamesE


People also ask

Can we use count with aggregate function in MongoDB?

The MongoDB $count operator allows us to pass a document to the next phase of the aggregation pipeline that contains a count of the documents. There a couple of important things to note about this syntax: First, we invoke the $count operator and then specify the string.

How do you count the no of documents retrieved from MongoDB?

count() The count() method counts the number of documents that match the selection criteria. It returns the number of documents that match the selection criteria.

What does MongoDB aggregate return?

aggregate() method returns a cursor to the documents produced by the final stage of the aggregation pipeline operation, or if you include the explain option, the document that provides details on the processing of the aggregation operation.

What are the differences between using aggregate () and find () MongoDB?

With aggregate + $match, you get a big monolithic BSON containing all matching documents. With find, you get a cursor to all matching documents. Then you can get each document one by one.


1 Answers

If I correctly understand what do you want, you could try this:

db.builds.aggregate([
    { $project: 
        { 
            time: 1,
            projectedData: { $ifNull: ['$data.buildResult', 'none'] } 
        } 
    },

    { $group: { 
        _id: { 
            month: { $month: "$time" },
            day: { $dayOfMonth: "$time" },
            year: { $year: "$time" }, 
            buildResult: "$projectedData"
        },
        count: { $sum: { $cond: [ { $eq: [ "$projectedData", "none" ] }, 0, 1 ] } }
    } },

    { $sort: { "_id.year": 1, "_id.month": 1, "_id.day": 1 } }
])

Update:
You want to get from output more documents that been in input, it is possible only with unwind operator that works with arrays, but you haven't any arrays, so as I know it is impossible to get more documents in your case. So you should add some logic after query result to create new data for existing dates with 0 count for another type of buildResult...

like image 143
Ivan.Srb Avatar answered Oct 03 '22 07:10

Ivan.Srb