Mongo:如何将所有使用 long timeStamp 的条目转换为 ISODate?

Posted

技术标签:

【中文标题】Mongo:如何将所有使用 long timeStamp 的条目转换为 ISODate?【英文标题】:Mongo : How to convert all entries using a long timeStamp to an ISODate? 【发布时间】:2015-10-09 18:16:53 【问题描述】:

我有一个当前的 Mongo 数据库,其中包含累积的条目/字段


 name: "Fred Flintstone",
 age : 34,
 timeStamp : NumberLong(14283454353543)



 name: "Wilma Flintstone",
 age : 33,
 timeStamp : NumberLong(14283454359453)

等等……

问题:我想将数据库中的所有条目转换为相应的 ISODate - 如何做到这一点?

期望的结果:


 name: "Fred Flintstone",
 age : 34,
 timeStamp : ISODate("2015-07-20T14:50:32.389Z")



 name: "Wilma Flintstone",
 age : 33,
 timeStamp : ISODate("2015-07-20T14:50:32.389Z")

我尝试过的事情

 >db.myCollection.find().forEach(function (document) 
    document["timestamp"] = new Date(document["timestamp"])

    //Not sure how to update this document from here
    db.myCollection.update(document) //?
)

【问题讨论】:

【参考方案1】:

你快到了,你只需要在修改后的文档上调用save() 方法来更新它,因为该方法使用 insertupdate 命令。在上面的例子中,文档包含一个_id 字段,因此save() 方法等价于一个 update() 操作,其中 upsert 选项设置为 true,查询谓词在 _id字段:

db.myCollection.find().snapshot().forEach(function (document) 
    document["timestamp"] = new Date(document["timestamp"]);
    db.myCollection.save(document)
)

以上内容类似于您之前尝试的显式调用 update() 方法:

db.myCollection.find().snapshot().forEach(function (document) 
    var date = new Date(document["timestamp"]);
    var query =  "_id": document["_id"] , /* query predicate */
        update =  /* update document */
           "$set":  "timestamp": date 
        ,
        options =  "upsert": true ;         

    db.myCollection.update(query, update, options);
)

对于相对较大的集合大小,您的数据库性能会很慢,建议使用mongo bulk updates:

MongoDB 版本 >= 2.6 和

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

db.myCollection.find("timestamp": "$not": "$type": 9 ).forEach(function (doc)     
    bulk.find( "_id": doc._id ).updateOne( 
        "$set":  "timestamp": new Date(doc.timestamp")  
    );

    counter++;
    if (counter % 1000 === 0) 
        // Execute per 1000 operations 
        bulk.execute(); 

        // re-initialize every 1000 update statements
        bulk = db.myCollection.initializeUnorderedBulkOp();
    
)

// Clean up remaining operations in queue
if (counter % 1000 !== 0) bulk.execute(); 

MongoDB 3.2 及更高版本:

var ops = [],
    cursor = db.myCollection.find("timestamp": "$not": "$type": 9 );

cursor.forEach(function (doc)      
    ops.push( 
        "updateOne":  
            "filter":  "_id": doc._id  ,              
            "update":  "$set":  "timestamp": new Date(doc.timestamp")   
                 
    );

    if (ops.length === 1000) 
        db.myCollection.bulkWrite(ops);
        ops = [];
         
);

if (ops.length > 0) db.myCollection.bulkWrite(ops);

【讨论】:

【参考方案2】:

在尝试从 NumberLong 值实例化 Date 对象时,mongo 中似乎发生了一些麻烦的事情。主要是因为 NumberLong 值被转换为错误的表示,并且使用了回退到当前日期。

我与 mongo 战斗了 2 天,终于找到了解决方案。关键是将 NumberLong 转换为 Double ...并将 double 值传递给 Date 构造函数。

这是使用灯泡操作并为我工作的解决方案...

(lastIndexedTimestamp是迁移到ISODate并存储在lastIndexed字段中的集合字段。创建一个临时集合,最后重命名为原始值。)

db.annotation.aggregate(    [
      $project:  
        _id: 1,
        lastIndexedTimestamp: 1,
        lastIndexed:  $add: [new Date(0), $add: ["$lastIndexedTimestamp", 0]]
        
    ,
     $out : "annotation_new" 
])

//drop annotation collection
db.annotation.drop();

//rename annotation_new to annotation
db.annotation_new.renameCollection("annotation");

【讨论】:

以上是关于Mongo:如何将所有使用 long timeStamp 的条目转换为 ISODate?的主要内容,如果未能解决你的问题,请参考以下文章

如何将所有 Meteor Mongo 集合名称检索为 Javascript 数组?

使用 GORM 获取 Mongo 集合时,找不到能够从 java.lang.Double 类型转换为 java.lang.Long 类型的转换器

如何在mongo spring boot中默认为所有查询添加默认条件

如何使用 Mongo 存储库两次查询同一字段?

如何使用spring data mongo更新所有行的特定列

如何列出 mongo shell 中的所有数据库?