Link to home
Start Free TrialLog in
Avatar of Crazy Horse
Crazy HorseFlag for South Africa

asked on

Count records of statuses(approved, pending, rejected) and return values into their own individual variables

I am trying to count database records in mongoDB (using mongoose) where records have a status of pending and approved as well as rejected. So, I am basically trying to get a result where I can show a count of each and display it in my view ie:

Pending: 35
 Approved: 97
 Rejected: 12

And I want to hold these in variables that I can use in different places ie:

const pending = ....
const approved = ....
const rejected = .....

I have tried to use the aggregate function and run a loop which gets me all the data I need but I don't know how to actually get the data into the three variables like above.

    Product.aggregate([
        { $group: { _id: { status: "$status" }, totalStatus: { $sum: 1 } } }

    ])

Open in new window


The above code gives me back this (I have no rejected values yet)

[
    {
        _id: {
            status: 'pending'
        },
        totalStatus: 15
    },
    {
        _id: {
            status: 'approved'
        },
        totalStatus: 27
    }
  ]

Open in new window


I then ran a loop and restructured the data:

        .then(status => {
            for (const current of status) {
                const [status, total] = [current._id.status, current.totalStatus];
                console.log(status + ': ' + total);
            }
            next();
        })

Open in new window


That gives me:

pending: 15
approved: 27

But it still isn't what I actually want. I need to get those values into their own variables. How can I do that?
ASKER CERTIFIED SOLUTION
Avatar of Zakaria Acharki
Zakaria Acharki
Flag of Morocco image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Crazy Horse

ASKER

Thanks for this answer. Is there a way to do it all in Mongoose though instead of me having to loop and use destructuring?
As I know that is not possible if you want a specific structure you need to adjust it manually after receiving the mongoose's result.
You should be able to get the result directly from the db. Something like:

const pending = Product.aggregate( [
    { $match: { status: "Pending" } },
    { $group: { _id: "_id", total: { $sum: 1} } }
] );

Open in new window


See docs here
Thanks Michael, that would only return the pending status and not approved and rejected though?
Yes you're matching on the status field = "Pending". All three constants would look like:

const pending = Product.aggregate( [
    { $match: { status: "Pending" } },
    { $group: { _id: "_id", total: { $sum: 1} } }
] );
const approved = Product.aggregate( [
    { $match: { status: "Approved" } },
    { $group: { _id: "_id", total: { $sum: 1} } }
] );
const rejected = Product.aggregate( [
    { $match: { status: "Rejected" } },
    { $group: { _id: "_id", total: { $sum: 1} } }
] );

Open in new window

Got it. But that is 3 different queries now. I had wanted to do it all in one query and try extract that way so I only hit the database once as opposed to 3 times. Or is there not much difference in performance?
Got it, I misunderstood. So your question is really how to get the values from your results array:
[   {
        _id: {
            status: 'pending'
        },
        totalStatus: 15
    },
    {
        _id: {
            status: 'approved'
        },
        totalStatus: 27
    }  ]

Open in new window


Zakaria Acharki provided an answer on that. You could also use .filter, something like:

var result = [ {
        _id: {
            status: 'pending'
        },
        totalStatus: 15
    },
    {
        _id: {
            status: 'approved'
        },
        totalStatus: 27
} ];
const pending = result.filter(item => item._id.status === "pending")[0].totalStatus;

Open in new window


Of course you're going to have to handle instances were the status is not present, like rejected. Something like:

var rejected = 0;
if (result.filter(item => item._id.status === "rejected")) {
  rejected = result.filter(item => item._id.status === "rejected")[0].totalStatus;
}

Open in new window