Index `hint` in pymongo aggregation query not working

I am using MongoDB version 4.0 and performing the following aggregate query.

db.collection.aggregate([
  "$match": {
            "$expr": {
              "$gte": [
                "$created_at",
                {
                  "$subtract": [
                    {
                      "$dateFromParts": {
                        "day": {
                          "$dayOfMonth": "$$NOW"
                        },
                        "hour": 0,
                        "millisecond": 0,
                        "minute": 0,
                        "month": {
                          "$month": "$$NOW"
                        },
                        "second": 0,
                        "timezone": "+0530",
                        "year": {
                          "$year": "$$NOW"
                        }
                      }
                    },
                    {
                      "$multiply": [
                        1,
                        86400000
                      ]
                    }
                  ]
                }
              ]
            }
          }
])

I have the below index in place, but its not getting used by the MongoDB query.

{
		"v" : 2,
		"key" : {
			"candidate_id" : 1,
			"created_at" : -1
		},
		"name" : "candCreatedAtIndex",
		"ns" : "proddb.applications",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"establishment_id" : 1,
			"created_at" : -1
		},
		"name" : "estCreatedAtIndex",
		"ns" : "proddb.applications",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"created_at" : -1
		},
		"name" : "createdAtIndex",
		"background" : true,
		"ns" : "proddb.applications"
	},

So, I made use of the $hint method to force MongoDB in using that aggregation query.

var dt = new Date();
db.applications.aggregate([
        {
          "$match": {
                "$expr": {
                  "$gte": [
                    "$created_at",
                    {
                      "$subtract": [
                        {
                          "$dateFromParts": {
                            "day": {
                              "$dayOfMonth": dt
                            },
                            "hour": 0,
                            "millisecond": 0,
                            "minute": 0,
                            "month": {
                              "$month": dt
                            },
                            "second": 0,
                            "timezone": "+0530",
                            "year": {
                              "$year": dt
                            }
                          }
                        },
                        {
                          "$multiply": [
                            1,
                            86400000
                          ]
                        }
                      ]
                    }
                  ]
                }
          },
        }
], {
  'hint': 'createdAtIndex'
}).explain()

When I use $hint in MQL, its utilizing the index for the $match query, but its still performing COLLSCAN in PyMongo.

Below is the PyMongo code I used.

dt = datetime.utcnow()
cursor = applications_col.aggregate([
        {
          "$match": {
                "$expr": {
                  "$gte": [
                    "$created_at",
                    {
                      "$subtract": [
                        {
                          "$dateFromParts": {
                            "day": {
                              "$dayOfMonth": dt
                            },
                            "hour": 0,
                            "millisecond": 0,
                            "minute": 0,
                            "month": {
                              "$month": dt
                            },
                            "second": 0,
                            "timezone": "+0530",
                            "year": {
                              "$year": dt
                            }
                          }
                        },
                        {
                          "$multiply": [
                            1,
                            86400000
                          ]
                        }
                      ]
                    }
                  ]
                }
          },
        }
], hint='createdAtIndex')

Indexes can only be used when a field is being compared to a constant value. Here you are computing a value on the fly so it’s not possible for index to be used.

If you want an index to be used, you can compute the date client side to compare created_at to and then the index on created_at field will be used.

Asya

2 Likes

Thanks for your response @Asya_Kamsky. I stored datetime object to a variable and the query uses indexes now!

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.