skip to Main Content

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?

3

Answers


  1. 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"
        }
      ]
    )
    
    
    
    
    Login or Signup to reply.
  2. 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
            ]
          }
        }
      }
    ])
    
    Login or Signup to reply.
  3. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search