How to use MongoDB date/time in filter

I’m trying to develop a locking mechanism that uses MongoDB’s date/time to know whether a lock has expired or not, and if so, get the lock. I’m using findOneAndUpdate() like this:

   {"_id": "my-lock","$or" :[{"state": {"$ne": "locked"}},{"lockedUntil": {"$lt": new Date()}}]},
   [ { $set: { "lastAcquiredAt": "$$NOW", "state": "locked", "lockedUntil" : { $add: ["$$NOW", 15000 ] } } } ],
   { upsert:true, returnNewDocument : true }

In the $set, I’m using $$NOW to get the current date/time, which works fine. However I can’t use that in the filter, where I’m checking if the current lock has expired and I can acquire it. How do I go about using MongoDB date/time in a filter? I can use new Date() to return it, but is that the best/only way? I’ve also tried adding a $match pipeline, but it’s not allowed using findOneAndUpdate().

To use “$$NOW” you have to use an aggregation expression, which you can do via $expr like this:

{"_id": "my-lock","$or" :[{"state": {"$ne": "locked"}},{"$expr":{"$lt":[ "$lockedUntil", "$$NOW"]}}]}

Unfortunately, even though you can use this to query for appropriate document, it turns out that upsert doesn’t allow $expr (I’m not sure why, to be honest)… So you’d get this error: "errmsg" : "$expr is not allowed in the query predicate for an upsert" which is too bad… :frowning:

P.S. we do have a note about it in our documentation but there is also a ticket for us to add support for this.

1 Like