10

This query which should filter results by the month seems to be working fine. But I can't figure out how to add a year filter as well.

db.collection.find({
  "$expr": {
    "$eq": [{ "$month": "$timestamp" }, 12]
  }
});

I tried to come up with something like this but no success.

db.collection.find({
  "$expr": {
    "$and": [
      { "$eq": [{ "$month": "$timestamp" }, 12] }, 
      { "$eq": [{ "$year": "$timestamp" }, 2018] }
    ]
  }
});

How to do that properly?

2 Answers2

20

I wanted to use find not aggregate. Adding another $eq with $and like this worked for me.

db.collection.find({
  $and: [
    { $expr: {$eq: [{$month: "$timestamp"}, 12]} },
    { $expr: {$eq: [{$year: "$timestamp"}, 2019]} }
  ]
});
rampanwar
  • 199
  • 1
  • 5
1

You can use aggregate instead of find.

A 3 step solution will work great:

  1. $project the year and month fields together with the document itself, using $$ROOT. Since $project outputs only the specified fields, we will need to project the document itself as well.
  2. Filter by the year and month you would like, using $match.
  3. $replaceRoot to bring the original document back to the top level (flatten it).
db.collection.aggregate([
  {
    "$project": {
      "year": { "$year": "$timestamp" },
      "month": { "$month": "$timestamp" },
      "document": "$$ROOT"
    }
  },
  {
    "$match": {
      "year": 2018,
      "month": 12
    }
  },
  {
    "$replaceRoot": { "newRoot": "$document" }
  }
])
Z-Bone
  • 1,534
  • 1
  • 10
  • 14