如何将使用长时间戳的所有条目转换为ISODate



我有一个具有累积条目/字段的当前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) //?
})

使用聚合管道进行更新操作,只需运行以下更新操作:

db.myCollection.updateMany(
   { },
   [
      {  $set: {
         timeStamp: { 
            $toDate: '$timeStamp'
         }
      } },
   ]
])

在您最初的尝试中,您几乎就在那里,您只需要在修改的文档上调用 save() 方法来更新它,因为该方法使用 insert update 命令。在上面的实例中,文档包含一个_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批量更新:

MongoDB版本>= 2.6 and <3.2:

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);

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

我和mongo打了2天,最后我找到了解决办法。关键是将NumberLong转换为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");

相关内容

最新更新