Beginner
Beginner

Reputation: 1740

Count posts of user with default value

Supposed I have a data of

[
    {
        "_id": "629eb5ced774223d36a68907",
        "userId": "629eb22698df1015e980a98f",
        "posts": [
            {
                "_id": "629eb59ad774223d36a688fa",
                "title": "titletestz",
                "body": "bodyz",
                "createdAt": "2022-06-07T02:19:06.314Z",
                "updatedAt": "2022-06-07T02:19:06.314Z",
                "__v": 0
            },
            {
                "_id": "629eb59ad774223d36a688fc",
                "title": "titletestx",
                "body": "bodyx",
                "createdAt": "2022-06-07T02:19:06.879Z",
                "updatedAt": "2022-06-07T02:19:06.879Z",
                "__v": 0
            }
        ],
        "createdAt": "2022-06-07T02:19:58.206Z",
        "updatedAt": "2022-06-07T02:19:58.206Z",
        "__v": 0
    },
    {
        "_id": "629ebf8b775b5cd326b1c41c",
        "userId": "629eb22698df1015e980a98f",
        "posts": [
            {
                "_id": "629eb22c98df1015e980a995",
                "title": "ttle3",
                "body": "ttile3",
                "createdAt": "2022-06-07T02:04:28.787Z",
                "updatedAt": "2022-06-07T02:04:28.787Z",
                "__v": 0
            }
        ],
        "createdAt": "2022-06-07T03:01:31.065Z",
        "updatedAt": "2022-06-07T03:01:31.065Z",
        "__v": 0
    }
]

I want to count the posts of a specific user

let start = new Date()
start = start.setHours(0,0,0,0)

let end = new Date()
end = start.setHours(23,59,59,999)

model.aggregate([
  {
    $match: {
      userId,
      createdAt: {
        $gte: start,
        $lt: end
      }
    }
  },
  {
    $unwind : '$posts',
  },
  {
    $count: 'count'
  }
])

now it does work

[
  {
    "total": 3
  }
]

however, I want to set a default value of 0 of user if it doesn't contain any posts, like this:

[
  {
    "total": 0
  }
]

right now I just having a response of an empty array [] if user doesn't have any posts.

any idea how can I achieve this using aggregate in monggo?

Upvotes: 1

Views: 657

Answers (3)

1sina1
1sina1

Reputation: 1086

using $facet and $ifNull

mongo playground

db.collection.aggregate([
  {
    "$facet": {
      count: [
        {
          $match: {
            userId,
            createdAt: {
              $gte: start,
              $lt: end
            }
          }
        },
        { $unwind: "$posts" },
        { "$count": "total" }
      ]
    }
  },
  {
    "$project": {
      "total": {
        "$ifNull": [
          { "$arrayElemAt": ["$count.total", 0] },
          0
        ]
      }
    }
  }
])

Upvotes: 2

nimrod serok
nimrod serok

Reputation: 16033

You better avoid unwind if possible. The simple way is just $group and $sum up the number of posts on each document. This will return 0 if there is no posts for this user. You can run it on multiple users together, if you want

EDIT: use $facet to solve users that has no documents:

db.collection.aggregate([
{
  $facet: {
    count: [{
      $match: {
        userId,
        createdAt: {$gte: start, $lt: end}
      }
    },
    {$group: {_id: "$userId", total: {$sum: {$size: "$posts"}}}}
  ]},
  {
    $project: {
      total: {$ifNull: [{$arrayElemAt: ["$count.total", 0]}, 0]}}
  }
])

See how it works on the playground example

Upvotes: 0

sai krishna
sai krishna

Reputation: 139

It Will return empty array on no matches.

let start = new Date()
start = start.setHours(0,0,0,0)

let end = new Date()
end = start.setHours(23,59,59,999);

db.collection.aggregate(
  [
    {
      $match: {
      userId,
      createdAt: {
        $gte: start,
        $lt: end
      }
    }
    },
    {
      $group: {
         '$posts'
      }
    },
    {
      $count: "totalCount"
    }
  ]
)



Upvotes: 0

Related Questions