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()
方法来更新它,因为该方法使用 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 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中默认为所有查询添加默认条件