MongoDB Aggregation Query Leap Year

I have a problem with queries.

Consider these documents:

{
    "_id" : ObjectId("63a994974ac549c5ea982d2b"),
    "title" : "Destroyer",
    "year" : 2018
},
{
    "_id" : ObjectId("63a994974ac549c5ea982d2a"),
    "title" : "Aquaman",
    "year" : 2014
},

{
    "_id" : ObjectId("63a994974ac549c5ea982d29"),
    "title" : "On the Basis of Sex",
    "year" : 1996   
},

{
    "_id" : ObjectId("63a994974ac549c5ea982d28"),
    "title" : "Holmes and Watson",
    "year" : 1940
},
{
    "_id" : ObjectId("63a994974ac549c5ea982d27"),
    "title" : "Conundrum: Secrets Among Friends",
    "year" : 1957
},
{
    "_id" : ObjectId("63a994974ac549c5ea982d26"),
    "title" : "Welcome to Marwen",
    "year" : 2004
},

{
    "_id" : ObjectId("63a994974ac549c5ea982d25"),
    "title" : "Mary Poppins Returns",
    "year" : 1997
},

{
    "_id" : ObjectId("63a994974ac549c5ea982d24"),
    "title" : "Bumblebee",
    "year" : 2004
}

I am trying to group all leap years in these documents. I tried this code:

var query0 = {$group: {"_id": {"year": "$year"}}}

var query1 = {$addFields: {
      leap: {
        "$and": [
          {"$eq": [{"$mod": ["$year",4]}, 0]},
          {"$or": [
              {"$ne": [{"$mod": ["$year", 100]}, 0]},
              {"$eq": [{"$mod": ["$year", 400]}, 0] }
          ]}
        ]
      }
}}

var query2 = {$project: {leap: true}}

var query3 = {$group: {
      "_id": "$leap",
      "count": {$sum: 1}
  }}

var etapas =  [query0, query1, query2, query3]

db.genres.aggregate(etapas)

But I get this output:

{
    "_id": false,
    "count": 8 
}

It is wrong because the expect output is this:

{
    "_id": Leap,
    "count": 3
}

I do not know what I am doing wrong.. but I cannot get the right output.

How can I fix this?

Thanks so much for your attention on me.

>Solution :

Based on your query, you will lose the $year field after the first $group stage.

  1. In the $group stage, add the year field.

  2. (Optional) The $project stage seems unnecessary.

  3. $group – You should conditionally sum the leap when $leap is true.

db.collection.aggregate([
  {
    $group: {
      "_id": {
        "year": "$year"
      },
      year: {
        $first: "$year"
      }
    }
  },
  {
    $addFields: {
      leap: {
        "$and": [
          {
            "$eq": [
              {
                "$mod": [
                  "$year",
                  4
                ]
              },
              0
            ]
          },
          {
            "$or": [
              {
                "$ne": [
                  {
                    "$mod": [
                      "$year",
                      100
                    ]
                  },
                  0
                ]
              },
              {
                "$eq": [
                  {
                    "$mod": [
                      "$year",
                      400
                    ]
                  },
                  0
                ]
              }
            ]
          }
        ]
      }
    }
  },
  {
    $group: {
      "_id": "Leap",
      "count": {
        $sum: {
          $cond: {
            if: {
              $eq: [
                "$leap",
                true
              ]
            },
            then: 1,
            else: 0
          }
        }
      }
    }
  }
])

Demo @ Mongo Playground


Or get the year value from _id.

db.collection.aggregate([
  {
    $group: {
      "_id": "$year"
    }
  },
  {
    $addFields: {
      leap: {
        "$and": [
          {
            "$eq": [
              {
                "$mod": [
                  "$_id",
                  4
                ]
              },
              0
            ]
          },
          {
            "$or": [
              {
                "$ne": [
                  {
                    "$mod": [
                      "$_id",
                      100
                    ]
                  },
                  0
                ]
              },
              {
                "$eq": [
                  {
                    "$mod": [
                      "$_id",
                      400
                    ]
                  },
                  0
                ]
              }
            ]
          }
        ]
      }
    }
  },
  {
    $group: {
      "_id": "Leap",
      "count": {
        $sum: {
          $cond: {
            if: {
              $eq: [
                "$leap",
                true
              ]
            },
            then: 1,
            else: 0
          }
        }
      }
    }
  }
])

Leave a Reply