取mongoDB中相邻文档之间的差异
taking the difference between adjacent documents in mongoDB
如何使用javascript获取mongoDB中相邻记录之间的差异?例如,如果我在一个集合中有以下三个文档:
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z")
}
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z")
}
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z")
}
我想取"时间"字段中相邻值之间的差异,以获得:
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z"),
"time_difference" : null
}
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z"),
"time_difference" : 1
}
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z"),
"time_difference" : 3
}
关于如何在javascript/mongoDB中高效地做到这一点,有什么想法吗?谢谢
我不知道七年前问这个问题时这是否属实,但这可以在聚合框架内完全解决。假设集合名称为AdjacentDocument
,则以下聚合将获得您要查找的结果:
db.AdjacentDocument.aggregate(
{$sort: {time: 1}},
{$group: {_id: 0, document: {$push: '$$ROOT'}}},
{$project: {documentAndPrevTime: {$zip: {inputs: ['$document', {$concatArrays: [[null], '$document.time']}]}}}},
{$unwind: {path: '$documentAndPrevTime'}},
{$replaceWith: {$mergeObjects: [{$arrayElemAt: ['$documentAndPrevTime', 0]}, {prevTime: {$arrayElemAt: ['$documentAndPrevTime', 1]}}]}},
{$set: {time_difference: {$trunc: [{$divide: [{$subtract: ['$time', '$prevTime']}, 1000]}]}}},
{$unset: 'prevTime'}
);
聚合管道演练
首先,文档从最旧到最新进行排序。它们被分组为一个文档,文档存储在有序数组字段中:
{$sort: {time: 1}},
{$group: {_id: 0, document: {$push: '$$ROOT'}}}
/*
{
"_id" : 0,
"document" : [
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z")
},
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z")
},
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z")
}
]
}
*/
接下来,将以前的时间压缩到文档数组中,创建一个[document, previousTime]
:数组
{$project: {documentAndPrevTime: {$zip: {inputs: ['$document', {$concatArrays: [[null], '$document.time']}]}}}}
/*
{
"_id" : 0,
"documentAndPrevTime" : [
[
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z")
},
null
],
[
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z")
},
ISODate("2013-02-13T15:45:41.148Z")
],
[
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z")
},
ISODate("2013-02-13T15:45:42.148Z")
]
]
}
*/
接下来,文档&时间数组展开,为每个初始文档创建一个文档:
{$unwind: {path: '$documentAndPrevTime'}}
/*
{
"_id" : 0,
"documentAndPrevTime" : [
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z")
},
null
]
}
{
"_id" : 0,
"documentAndPrevTime" : [
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z")
},
ISODate("2013-02-13T15:45:41.148Z")
]
}
{
"_id" : 0,
"documentAndPrevTime" : [
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z")
},
ISODate("2013-02-13T15:45:42.148Z")
]
}
*/
接下来,我们将文档替换为文档数组元素的值,并与上一个时间元素合并(如果是初始索引,则使用null):
{$replaceWith: {$mergeObjects: [{$arrayElemAt: ['$documentAndPrevTime', 0]}, {prevTime: {$arrayElemAt: ['$documentAndPrevTime', 1]}}]}}
/*
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z"),
"prevTime" : null
}
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z"),
"prevTime" : ISODate("2013-02-13T15:45:41.148Z")
}
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z"),
"prevTime" : ISODate("2013-02-13T15:45:42.148Z")
}
*/
最后,我们通过将time_difference
设置为两个时间字段的差来更新文档,并删除临时prevTime
字段。由于两个日期之间的差异以毫秒为单位,并且您的示例使用秒,因此我们通过除以1000并截断来计算秒。
{$set: {time_difference: {$trunc: [{$divide: [{$subtract: ['$time', '$prevTime']}, 1000]}]}}},
{$unset: 'prevTime'}
/*
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z"),
"time_difference" : null
}
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z"),
"time_difference" : 1
}
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z"),
"time_difference" : 3
}
*/
这里需要确保的一件事是,您对要用来装饰记录的查询进行了排序。如果不使用排序,它将实际使用find顺序,而不是$natural
顺序。
查询之间的查找顺序可能不同,因此如果您在2分钟内运行两次查询,您可能会发现它们不会返回相同的顺序。然而,您的查询似乎在tiem_difference
上进行了逻辑排序。
还应该注意的是,这是不可能通过正常查询实现的。我也看不到通过聚合框架实现这一点的简单方法。
因此,似乎下一个可行的方法是使用多个查询或客户端处理。使用上面@Marlon定义的函数,客户端处理可能会更好。
有一件事,我想清除你。与MYSQL不同的是,MongoDB并没有保证这个位置。我的意思是,MongoDB会在不同的时间给你不同的排序。因此,在每次阅读时,比较相邻的文档可能会得到不同的结果。
如果你对此很满意,并且你想进行比较,那么试试MongoDB的MapReducehttp://docs.mongodb.org/manual/applications/map-reduce/
假设这3个对象在一个数组中通过,您可以执行如下操作:
var prevTime;
var currentTime;
for(var i = 0; i < records.length; i++)
{
currentTime = new Date(records[i].time).getTime();
records[i].time_difference = currentTime - prevTime;
prevTime = currentTime;
}
当然,您需要交换比特,使其使用mongo中的记录。
如果你需要做任何更复杂的日期计算,我强烈建议你检查一下datejs(如果你愿意,你可以得到一个节点包装器)。
- JavaScript-使用sessionStorage保存文档之间共享的复选框状态
- 文档和元素之间的关系是什么?为什么父元素也有getElementsByTagName方法
- Couchdb/Pouchdb多个用户和多个文档之间的关系
- 在文档之间使用jQuery的Javascript不起作用
- 一个html的id甚至可以在相互引用的不同html文档之间关联吗
- 使用嵌入式文档列表和使用ObjectId列表之间有区别吗
- 如何查找iframe中某一点与iframe文档顶部之间的高度
- 获取元素与文档顶部之间的距离
- 使用easyXDM在父文档和从不同域(amazon)加载的子iframe之间进行通信
- 两个窗口或选项卡之间的跨文档消息传递,而不是iframe
- 共享文档.页面之间准备好javascript
- 谷歌云端点文档之间的差异,以及在我的应用程序中的工作
- IFrame和IFrame之间的跨文档消息传递问题家长
- 使用视图在couchDB中的各个文档之间返回唯一值
- 无法获取文档.execCommand('undo')在浏览器之间以相同的方式工作
- 在两个视图之间移动文档
- 流星,MongoDB.从集合中获取数据的麻烦(查找两个日期之间的文档)
- 在文档之间移动整个html页面上下文
- 取mongoDB中相邻文档之间的差异
- 文档和文档之间的区别