在日期时间的月、日、年...上查询 Mongodb

Posted

技术标签:

【中文标题】在日期时间的月、日、年...上查询 Mongodb【英文标题】:Query Mongodb on month, day, year... of a datetime 【发布时间】:2011-12-29 12:22:13 【问题描述】:

我正在使用 mongodb,并以这种方式将日期时间存储在我的数据库中

对于日期“17-11-2011 18:00”我存储:

date = datetime.datetime(2011, 11, 17, 18, 0)
db.mydatabase.mycollection.insert("date" : date)

我想做这样的请求

month = 11
db.mydatabase.mycollection.find("date.month" : month)

day = 17
db.mydatabase.mycollection.find("date.day" : day)

有人知道怎么做这个查询吗?

【问题讨论】:

我的方法遇到了一些性能问题,只有在别无选择的情况下才使用(参考我的帖子和 cmets)。相反,DrColossos 的回答是做到这一点的最佳方式......请接受他的回答 这显然不是重复的。如果这个问题中描述的语法方式实际上有一天会在 MongoDB 中实现,那么我们永远不会在另一个问题的答案中找到它,因为他们要求两个完全不同的东西(比较日期属性与在时间跨度内查找) )。解决方案碰巧是相同的,但它们不是必须的,理论上可能(也许有一天)会有所不同。 【参考方案1】:

日期以其时间戳格式存储。如果您想要属于特定月份的所有内容,请查询月份的开始和结束。

var start = new Date(2010, 11, 1);
var end = new Date(2010, 11, 30);

db.posts.find(created_on: $gte: start, $lt: end);
//taken from http://cookbook.mongodb.org/patterns/date_range/

【讨论】:

这是唯一的方法吗?是否有可能只在我的数据库中检索我的日期对象的月份? @DrColossos,还有另一种使用 $where 的方法 @DrColossos,看来你的方法比我的好.. $where 表达式有一些性能问题,请查看我的答案以获取更多信息... 您需要在end 上加上一天,以确保包含所有 31 天。顺便说一句,month=11 是 12 月,而不是 11 月。 Op 似乎指的是 Nov. 哇,这很糟糕还是什么...如果您想按特定日期查询,则必须注意天数和月末....月份可以有28个, 29 天、30 天或 31 天……他们为什么不能做类似的事情:日期: $year: 2014, $month:4 ?这不是查询语言,而是编程。【参考方案2】:

您不能直接按日期或月份等日期组件查询 mongodb 集合。但它可以通过使用特殊的 $where javascript 表达式

db.mydatabase.mycollection.find($where : function()  return this.date.getMonth() == 11 )

或者干脆

db.mydatabase.mycollection.find($where : 'return this.date.getMonth() == 11')

(但我更喜欢第一个)

查看以下 shell 命令以获取日期部分

>date = ISODate("2011-09-25T10:12:34Z")
> date.getYear()
111
> date.getMonth()
8
> date.getdate()
25

编辑:

只有在别无选择时才使用 $where。它伴随着性能问题。请查看@kamaradclimber 和@dcrosta 提供的以下cmets。我会让这篇文章打开,以便其他人了解它的事实。

查看链接$where Clauses and Functions in Queries了解更多信息

【讨论】:

这是一个方便的想法,但是如果你想获得良好的性能,真的不鼓励使用 $where :它需要一个全局锁。请参阅@DrColossos 答案以获得更好的方法。 @kamaradclimber,是的,没错,我知道这比本地运算符慢,因为没有使用索引。但我不确定全局锁定..你确定..?任何确认该声明的链接都非常有帮助.... 我在文档中没有发现任何锁定痕迹。这是性能损失的链接:mongodb.org/display/DOCS/…。我想我从 db.eval 段落中得到了锁的想法,所以让我们忘记它:-) DrColossos 的回答还是要快很多 它本身不是一个锁,但每个mongod 实例只有一个javascript 上下文来执行任何javascript($where、map-reduce 作业等)。查询将定期产生,因此一个查询不会完全阻止另一个查询,但多个查询或其他 javascript 工作会更慢。这就是不推荐$where 的原因。【参考方案3】:

既然您需要查询月份,那么如何将月份存储在它自己的属性中?不如$where 优雅,但可能表现更好,因为它可以被索引。

【讨论】:

好多了,这是正确的做法(AKA index ^^)。【参考方案4】:

如果您要搜索属于特定月份的文档,请确保像这样查询:

// Anything greater than this month and less than the next month
db.posts.find(created_on: $gte: new Date(2015, 6, 1), $lt: new Date(2015, 7, 1));

尽量避免像下面这样的查询。

// This may not find document with date as the last date of the month
db.posts.find(created_on: $gte: new Date(2015, 6, 1), $lt: new Date(2015, 6, 30));

// don't do this too
db.posts.find(created_on: $gte: new Date(2015, 6, 1), $lte: new Date(2015, 6, 30));

【讨论】:

一般的伟大原则。日期搜索应该几乎总是有一个包含的开始日期和一个不包含的结束日期。【参考方案5】:

您可以通过日期聚合运算符,如$dayOfYear、$dayOfWeek、$month、$year等按月、日、年等查找日期记录。

例如,如果您想要在 2016 年 4 月创建的所有订单,您可以使用以下查询。

db.getCollection('orders').aggregate(
   [
     
       $project:
         
           doc: "$$ROOT",
           year:  $year: "$created" ,
           month:  $month: "$created" ,
           day:  $dayOfMonth: "$created" 
         
     ,
      $match :  "month" : 4, "year": 2016  
   ]
)

这里创建的是文档中的日期类型字段,$$ROOT 我们用来将所有其他字段传递给下一阶段的项目,并为我们提供文档的所有详细信息。

您可以根据需要优化上述查询,这只是举例。要了解有关日期聚合运算符的更多信息,请访问the link。

【讨论】:

如果我想做一个随机的一个月的一年和一天,它会是什么样子 @Punnet Singh,先生,我想要依赖于 createdAt 的月份数据如何修复?我从邮递员发送月份值【参考方案6】:

您可以使用MongoDB_DataObject wrapper 来执行如下查询:

$model = new MongoDB_DataObject('orders');

$model->whereAdd('MONTH(created) = 4 AND YEAR(created) = 2016');

$model->find();

while ($model->fetch()) 
    var_dump($model);

或者,类似地,使用直接查询字符串:

$model = new MongoDB_DataObject();

$model->query('SELECT * FROM orders WHERE MONTH(created) = 4 AND YEAR(created) = 2016');

while ($model->fetch()) 
    var_dump($model);

【讨论】:

【参考方案7】:

使用$expr 运算符,它允许在查询语言中使用聚合表达式。这将使您能够在查询中使用Date Aggregation Operators,如下所示:

month = 11
db.mydatabase.mycollection.find( 
    "$expr":  
        "$eq": [  "$month": "$date" , month ] 
     
)

day = 17
db.mydatabase.mycollection.find( 
    "$expr":  
        "$eq": [  "$dayOfMonth": "$date" , day ] 
     
)

您还可以使用aggregate() 函数运行聚合操作,该函数接受$redact 管道:

month = 11
db.mydatabase.mycollection.aggregate([
    
        "$redact": 
            "$cond": [
                 "$eq": [  "$month": "$date" , month ] ,
                "$$KEEP",
                "$$PRUNE"
            ]
        
    
])

其他请求

day = 17
db.mydatabase.mycollection.aggregate([
    
        "$redact": 
            "$cond": [
                 "$eq": [  "$dayOfMonth": "$date" , day ] ,
                "$$KEEP",
                "$$PRUNE"
            ]
        
    
])

使用 OR

month = 11
day = 17
db.mydatabase.mycollection.aggregate([
    
        "$redact": 
            "$cond": [
                 
                    "$or": [ 
                         "$eq": [  "$month": "$date" , month ] ,
                         "$eq": [  "$dayOfMonth": "$date" , day ] 
                    ] 
                ,
                "$$KEEP",
                "$$PRUNE"
            ]
        
    
])

使用与

var month = 11,
    day = 17;
db.collection.aggregate([
    
        "$redact": 
            "$cond": [
                 
                    "$and": [ 
                         "$eq": [  "$month": "$createdAt" , month ] ,
                         "$eq": [  "$dayOfMonth": "$createdAt" , day ] 
                    ] 
                ,
                "$$KEEP",
                "$$PRUNE"
            ]
        
    
])

$redact 运算符结合了 $project$match 管道的功能,并将返回所有符合条件的文档使用$$KEEP 并使用 $$PRUNE 变量从管道中丢弃不匹配的那些。

【讨论】:

以上是关于在日期时间的月、日、年...上查询 Mongodb的主要内容,如果未能解决你的问题,请参考以下文章

查询两个日期相差的月数和剩下的天数

在飞镖中添加/减去迄今为止的月/年?

按日期时间的月/日订购 Django QuerySet?

将两个给定日期之间的月、年和日计算为时间戳[重复]

如何在查询语句 Mysql 中格式化日期?

如何计算两个日期之间的月数和天数,而不在 SQL Server 中返回负值