简体   繁体   中英

MongoDB query Date field with the server time

I have mongo documents with field containing date that I insert using $currentDate, so the field has the mongo server date when I insert the document. I want to query and filter all documents that the difference between the date field and the server date is more then 10 minutes.

Assume this db:

{ "_id" : 1, "item" : "abc", "price" : 10, "fee" : 2, "discount" : 5, "date" : ISODate("2017-07-14T08:00:00Z") }
{ "_id" : 2, "item" : "jkl", "price" : 20, "fee" : 1, "discount" : 2, "date" : ISODate("2017-07-14T08:05:00Z") }

Assume I will run the query on "2017-07-14T08:10:01Z" server date, I want that the query will return only the first item.

db.items.aggregate([
{$project : {lut : {$subtract: ["** server date **", "$date" ]}}}, 
{$match : { lut : {$gte : 10*60*1000 }}} ]);

How do I get the server date when I'm running the query? I'm running the query from my nodeJS server replacing server date with new Date() will get the date of the node server and not the mongo server.

This is more trickier than it seems at first glance. When replication and sharding are involved, it is difficult to guarantee a perfect synchronization between the clocks on all the Mongo instances. This is the reason $currentDate wasn't extended for queries as explained by the development team [on this ticket].

That being said, a perfect solution doesn't exist, but we can think about workarounds. The serverStatus function returns information about the Mongo cluster including the server time. You could call this function while initializing the client code and find the difference between the client time and server time. Having this difference, you can make queries based on the client time corrected with the difference. Here's a Python snippet:

import datetime
import pymongo
client = pymongo.MongoClient()
db = client.test_Db
server_time = db.command("serverStatus")['localTime']
local_time = datetime.datetime.now()
difference = server_time - local_time


db.test_collection.find({'date': {'$lt': datetime.datetime.now() - datetime.timedelta(minutes=10) + difference}})

Be aware that this has an error between the moment the time is measured on the server and the time it is measured on the client. This error is influenced by the duration the information is being sent from the server to the client. Depending on your usecase you could have more or fewer documents returned from the database. If you first get the time on the client and then on the server, you will receive documents older than 10 minutes + the error so you will miss some documents. On the other hand, if you first get the time on the server and then on the client you will receive the documents older than 10 minutes - error , so you'll get a few extra documents. It's up if any of the cases is acceptable or not.

Another thing to consider is that putting just one limit you will receive more and more documents because there will be more and more documents updated at a time older than 10 minutes. Also, you'll receive the same documents over and over again. You should think about also putting a lower limit.

the mongodb server allow as to update field using the $currentDate operator but I did not find any option to use the date as in a query filter.

but there is an option to use "Store a JavaScript Function on the Server" https://docs.mongodb.com/manual/tutorial/store-javascript-function-on-server/ and add a function that will return the date.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM