获取 mongoDB 中相邻文档之间的差异

use*_*316 5 javascript mongodb mongodb-query

如何使用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")
}
Run Code Online (Sandbox Code Playgroud)

我想取相邻值之间“时间”字段的差异来获取:

{
    "_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
}
Run Code Online (Sandbox Code Playgroud)

关于如何在 javascript/mongoDB 中有效地做到这一点有什么想法吗?谢谢。

M. *_*tin 7

我不知道七年前问这个问题时是否是这样,但这可以在聚合框架内完全解决。假设集合名称为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'}
);
Run Code Online (Sandbox Code Playgroud)

聚合管道演练

首先,文档按从最旧到最新的顺序排序。它们被分组为一个文档,文档存储在有序数组字段中:

{$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")
        }
    ]
}
*/
Run Code Online (Sandbox Code Playgroud)

接下来,前面的时间被压缩到文档数组中,创建一个数组[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")
        ]
    ]
}
*/
Run Code Online (Sandbox Code Playgroud)

接下来,展开文档和时间数组,为每个初始文档创建一个文档:

{$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")
    ]
}
*/
Run Code Online (Sandbox Code Playgroud)

接下来,我们将文档替换为文档数组元素的值,并与前一个时间元素合并(如果是初始索引,则使用 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")
}
*/
Run Code Online (Sandbox Code Playgroud)

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
}
*/
Run Code Online (Sandbox Code Playgroud)


HIL*_*EEN 1

一件事,我想澄清你。与 MYSQL 不同,MongoDB 不提供位置保证。我的意思是,MongoDB 会在不同的时间给你不同的排序。因此,每次阅读时比较相邻文档可能会给出不同的结果。

如果您对此感到满意并且想要进行比较,请尝试使用 MongoDB 的 MapReduce http://docs.mongodb.org/manual/applications/map-reduce/