如何使用 mongo 聚合将字符串转换为日期?

Posted

技术标签:

【中文标题】如何使用 mongo 聚合将字符串转换为日期?【英文标题】:How can convert string to date with mongo aggregation? 【发布时间】:2016-04-22 14:33:22 【问题描述】:

在一个集合中,我存储了这种文档


    "_id" : 1,
    "created_at" : "2016/01/01 12:10:10",
    ...
.

    "_id" : 2,
    "created_at" : "2016/01/04 12:10:10",
    ...

我想使用聚合管道查找具有“creared_at”> 2016/01/01 的文档。

任何人都有将“created_at”转换为日期的解决方案,以便在聚合中进行比较?

【问题讨论】:

在聚合管道中无法将字符串转换为日期,而可以将日期转换为字符串。您可能会欺骗:创建您的收藏的副本并将created_at 存储为 ISODate,然后比较日期... 您实际上不需要为查询转换任何内容; created_at: $gt: '2016/01/01' 在这里可以正常工作,因为您的字符串格式支持有意义的比较。 @JohnnyHK:效果很好,我不认识它。非常感谢 【参考方案1】:

正如您所提到的,您需要首先更改您的架构,以便 created_at 字段包含日期对象而不是当前情况下的字符串,然后您可以使用 find() 查询您的集合 方法或聚合框架。前者将是最简单的方法。

要将created_at 转换为日期字段,您需要在循环中使用forEach() 方法迭代find() 方法返回的光标将 created_at 字段转换为 Date 对象,然后使用 $set 运算符更新该字段。

利用 Bulk API 进行批量更新,这提供了更好的性能,因为您将以 1000 个批量将操作发送到服务器,这会为您提供更好的性能,因为您不是将每个请求发送到服务器,每 1000 个请求中仅发送一次。

下面演示了这种方法,第一个示例使用了 MongoDB 版本>= 2.6 and < 3.2 中可用的 Bulk API。它更新所有 通过将 created_at 字段更改为日期字段来获取集合中的文档:

var bulk = db.collection.initializeUnorderedBulkOp(),
    counter = 0;

db.collection.find("created_at": "$exists": true, "$type": 2 ).forEach(function (doc) 
    var newDate = new Date(doc.created_at);
    bulk.find( "_id": doc._id ).updateOne( 
        "$set":  "created_at": newDate
    );

    counter++;
    if (counter % 1000 == 0) 
        bulk.execute(); // Execute per 1000 operations and re-initialize every 1000 update statements
        bulk = db.collection.initializeUnorderedBulkOp();
    
)
// Clean up remaining operations in queue
if (counter % 1000 != 0)  bulk.execute(); 

下一个示例适用于自 deprecated the Bulk API 以来的新 MongoDB 版本 3.2,并使用 bulkWrite() 提供了一组更新的 api:

var cursor = db.collection.find("created_at": "$exists": true, "$type": 2 ),
    bulkOps = [];

cursor.forEach(function (doc)  
    var newDate = new Date(doc.created_at);
    bulkOps.push(         
         
            "updateOne":  
                "filter":  "_id": doc._id  ,              
                "update":  "$set":  "created_at": newDate   
                     
                   
    );   

    if (bulkOps.length === 1000) 
        db.collection.bulkWrite(bulkOps);
        bulkOps = [];
    
);         

if (bulkOps.length > 0)  db.collection.bulkWrite(bulkOps); 

架构修改完成后,您可以查询您的集合的日期:

var dt = new Date("2016/01/01");
db.collection.find( "created_at":  "$gt": dt  );

如果您希望使用聚合框架进行查询,请运行以下管道以获得所需的结果。它使用 $match 运算符,类似于 find() 方法:

var dt = new Date("2016/01/01");
db.collection.aggregate([
    
        "$match":  "created_at":  "$gt": dt  
    
])

【讨论】:

我知道这是一个老歌,但在你的 Monbodb > v3.2 答案中,db.collection.bulkWrite(bulkUpdateOps); 应该是 db.collection.bulkWrite(bulkOps); @PhilippeHaussmann 好地方 ;) 我已修正错字,谢谢 没问题!代码 sn-p 对我现在正在做的事情非常有帮助。谢谢你把它放在一起! :D 你能帮忙解决这个问题吗? ***.com/questions/61165765/…【参考方案2】:

以上所有答案都使用cursors,但是,mongodb 始终建议使用aggregation 管道。使用mongodb 3.6 中的新$dateFromString,它非常简单。 https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromString/

db.collection.aggregate([
    $project: created_at:$dateFromString:dateString:'$created_at'
])

【讨论】:

嗨,有没有什么方法可以将日期作为字符串列搜索为实际日期列而不进行转换? 有人可以帮忙吗? ***.com/questions/61165765/…【参考方案3】:

如果我们有文件:

db.doc.save( "_id" : 1, "created_at" : "2016/01/01 12:10:10" )
db.doc.save( "_id" : 2, "created_at" : "2016/01/04 12:10:10" )

简单查询:

db.doc.find( "created_at" : "$lte": Date() )

聚合查询:

db.doc.aggregate([ 
     "$match":  "created_at":  "$lte": Date()  
])
Date() 方法以字符串形式返回当前日期。 使用 ISODate() 包装器返回 Date 对象的新 Date() 构造函数。 ISODate() 构造函数,它使用 ISODate() 返回一个 Date 对象 包装。

更多关于日期类型here和here的信息

【讨论】:

以上是关于如何使用 mongo 聚合将字符串转换为日期?的主要内容,如果未能解决你的问题,请参考以下文章

markdown Mongo DB Query将字符串转换为日期,然后按日期聚合。

将 SQL 查询转换为 Mongo 聚合

使用SQL将字符串列转换为mongodb中的日期时间

如何查询将日期存储为某种格式的字符串的 mongo 集合?

使用 SQL 将字符串列转换为 mongodb 中的日期时间

将字符串字段转换为 MongoDB 中的编码字符串