如何将我的SQL查询转换为MongoDB查询?

时间:2017-11-14 12:35:09

标签: mysql sql mongodb transform

我将时间序列数据从SQL迁移到MongoDB。我给你举个例子:

我们假设我们有一个带ID的测量设备,每分钟读取一次值。因此,每天,我们有24小时* 60分钟=该设备的1440值。

在SQL中,我们每天为此设备提供1440行:

ID          Timestamp                Value
400001       01.01.2017 00:00:00      ...
""           01.01.2017 00:01:00      ...
""                  ...               ...
""           01.01.2017 23:59:00      ...

我将数据迁移到MongoDB,我现在每天有一个文档,其值分配到24小时数组,分别包含60分钟包含值的字段(只有一个时间戳,日期为XX-XX-XXXX 00: 00:00):

{ ID: 400001, Timestamp: 01.01.2017 00:00:00, Hours: [ 0: [0: ..., 1: ..., 2: ..., ....... 59: ... ], 1: [0: ..., 1: ..., 2: ..., ....... 59: ... ], . . 23: [0: ..., 1: ..., 2: ..., ....... 59: ... ] ] }

我的问题是: 我想将以下SQL语句转换为mongoDB:

SELECT (Val) AS Val, (UNIX_TIMESTAMP(DATE_FORMAT(ArrivalTime, '%Y-%m-%d %H:%i:00'))) * 1000 AS timestmp FROM database WHERE ID = 400001 AND ArrivalTime BETWEEN FROM_UNIXTIME(1470002400) AND FROM_UNIXTIME(1475272800) ORDER BY ArrivalTime ASC

输出 enter image description here

因为在MongoDB中我只保存时间戳,然后将值拆分为数组,我没有像SQL中那样为每个值设置时间戳。因此,如果我想要例如,获取01.01.2017 02:14:00和01.01.2017 18:38:00之间的值,我该怎么做?

我制作了一个MongoDB查询,可以在两天之内给出值:

db.getCollection('test').aggregate([{$match: {ID: '400001', $and: [ {Timestamp_day: {$gte: new ISODate("2016-08-01 00:00:00.000Z")}}, {Timestamp_day: {$lte: new ISODate("2016-10-01 00:00:00.000Z")}}]}},{$unwind:"$Hours"}, {$unwind:"$Hours"}, {$group: {_id: '$Timestamp_day', Value: {$push: "$Hours"}}}, {$sort: {_id: 1}}]);

输出 enter image description here

但是我需要像在SQL中一样,我也可以在几个小时内给出值,并且每个值都给出正确的时间戳。

我希望你能帮助我。

2 个答案:

答案 0 :(得分:0)

这应该让你前进:

db.collection.aggregate([{
    $match: {
        "ID": '400001',
        "Timestamp_day": {
            $gte: new ISODate("2017-01-01T00:00:00.000Z"),
            $lte: new ISODate("2017-01-01T00:00:00.000Z")
        }
    }
}, {
    $unwind: {
      path: "$Hours",
      includeArrayIndex: "Hour"
    }
}, {
    $unwind: {
      path: "$Hours",
      includeArrayIndex: "Minute"
    }
}, {
    $project: {
        "_id": 0, // remove the "_id" field
        "Val": "$Hours", // rename "Hours" to "Val"
        "Timestamp": { // "resolve" our timestamp...
            $add: // ...by adding
            [
                { $multiply: [ "$Hour", 60 * 60 * 1000 ] }, // ...the number of hours in milliseconds
                { $multiply: [ "$Minute", 60 * 1000 ] }, // ...plus the number of minutes in milliseconds
                "$Timestamp_day", // to the "Timestamp_day" value
            ]
        }
    }
}, {
    $sort: {
        "Timestamp": 1 // oh well, sort by timestamp ascending
    }
}]);

输入文件

{
    "_id" : ObjectId("5a0e7d096216d24dd605cdec"),
    "ID" : "400001",
    "Timestamp_day" : ISODate("2017-01-01T00:00:00.000Z"),
    "Hours" : [ 
        [ 
            0.0, 
            0.1, 
            2.0
        ], 
        [ 
            1.0, 
            1.1, 
            2.1
        ], 
        [ 
            2.0, 
            2.1, 
            2.2
        ]
    ]
}

结果如下:

/* 1 */
{
    "Val" : 0.0,
    "Timestamp" : ISODate("2017-01-01T00:00:00.000Z")
}

/* 2 */
{
    "Val" : 0.1,
    "Timestamp" : ISODate("2017-01-01T00:01:00.000Z")
}

/* 3 */
{
    "Val" : 2.0,
    "Timestamp" : ISODate("2017-01-01T00:02:00.000Z")
}

/* 4 */
{
    "Val" : 1.0,
    "Timestamp" : ISODate("2017-01-01T01:00:00.000Z")
}

/* 5 */
{
    "Val" : 1.1,
    "Timestamp" : ISODate("2017-01-01T01:01:00.000Z")
}

/* 6 */
{
    "Val" : 2.1,
    "Timestamp" : ISODate("2017-01-01T01:02:00.000Z")
}

/* 7 */
{
    "Val" : 2.0,
    "Timestamp" : ISODate("2017-01-01T02:00:00.000Z")
}

/* 8 */
{
    "Val" : 2.1,
    "Timestamp" : ISODate("2017-01-01T02:01:00.000Z")
}

/* 9 */
{
    "Val" : 2.2,
    "Timestamp" : ISODate("2017-01-01T02:02:00.000Z")
}

<强>更新

根据您的评论,您需要计算任何值与其相应的先前值之间的差异。这可以通过以下方式完成 - 可能有更好的方法来实现相同的东西,但是......第一部分几乎与上面的解决方案完全相同,只是它有一个额外的$ match阶段来根据你的规范删除空值。

db.collection.aggregate([{
    $match: {
        "ID": '400001',
        "Timestamp_day": {
            $gte: new ISODate("2017-01-01T00:00:00.000Z"),
            $lte: new ISODate("2017-01-01T00:00:00.000Z")
        }
    }
}, {
    $unwind: {
      path: "$Hours",
      includeArrayIndex: "Hour"
    }
}, {
    $unwind: {
      path: "$Hours",
      includeArrayIndex: "Minute"
    }
}, {
    $match: {
        "Hours": { $ne: null } // get rid of all null values
    }
}, {
    $project: {
        "_id": 0, // remove the "_id" field
        "Val": "$Hours", // rename "Hours" to "Val"
        "Timestamp": { // "resolve" our timestamp...
            $add: // ...by adding
            [
                { $multiply: [ "$Hour", 60 * 60 * 1000 ] }, // ...the number of hours in milliseconds
                { $multiply: [ "$Minute", 60 * 1000 ] }, // ...plus the number of minutes in milliseconds
                "$Timestamp_day", // to the "Timestamp_day" value
            ]
        }
    }
}, {
    $sort: {
        "Timestamp": 1 // oh well, sort by timestamp ascending
    }
}, {
    $group: {
        "_id": null, // throw all documents in the same aggregated document
        "Docs": {
            $push: "$$ROOT" // and store our documents in an array
        }
    }
}, {
    $unwind: {
        path: "$Docs", // we flatten the "values" array
        includeArrayIndex: "Docs.Index", // this will give us the index of every element - there might be more elegant solutions using $map and $let...
    }
}, {
    $group: { // YES, unfortunately a second time... but this time we have the array index for each element
        "_id": null, // throw all documents in the same aggregated document
        "Docs": {
            $push: "$Docs" // and store our documents in an array
        }
    }
}, {
    $addFields: {
        "Docs": {
            $let: {
                vars: { "shiftedArray": { $concatArrays: [ [ null ], "$Docs.Val" ] } }, // shift value array by one to the right and put a null object at the start
                in: {
                    $map: {
                        input: "$Docs",
                        as: "d",
                        in: {
                            "Timestamp" : "$$d.Timestamp",
                            "Val": { $ifNull: [ { $abs: { $subtract: [ "$$d.Val", { $arrayElemAt: [ "$$shiftedArray", "$$d.Index" ] } ] } }, 0 ] }
                        }
                    }
                }
            }
        }
    }
}, {
    $unwind: "$Docs"
}, {
    $replaceRoot: {
        newRoot: "$Docs"
    }
}]);

使用示例数据集的结果如下所示:

/* 1 */
{
    "Timestamp" : ISODate("2017-01-01T00:00:00.000Z"),
    "Val" : 0.0
}

/* 2 */
{
    "Timestamp" : ISODate("2017-01-01T00:01:00.000Z"),
    "Val" : 0.0
}

/* 3 */
{
    "Timestamp" : ISODate("2017-01-01T00:02:00.000Z"),
    "Val" : 2.0
}

/* 4 */
{
    "Timestamp" : ISODate("2017-01-01T00:04:00.000Z"),
    "Val" : 3.0
}

/* 5 */
{
    "Timestamp" : ISODate("2017-01-01T00:05:00.000Z"),
    "Val" : 0.0
}

/* 6 */
{
    "Timestamp" : ISODate("2017-01-01T00:06:00.000Z"),
    "Val" : 1.0
}

答案 1 :(得分:0)

Eventuellkönntestdumir nochmal helfen,auch einTippwürdereichen@dnickless ..Ichbräuchteine查询die mir den Betrag der Differenz zum vorherig gemessenen Wert gibt(在einem bestimmten Zeitraum,zu einer bestimmten ID)。

als Beispiel:     Timestamp_day: ISODate("2017-01-01T01:00:00.000Z"), Hours: [ [ 1.0, 1.0, -1.0, null, 2.0, 2.0, 3.0, ... ], [ ... ], ... ]

Und dann als输出:

{
  'Timestamp' : ISODate("2017-01-01T00:00:00.000Z"),
  'Val' : 0.0 /* nix - 1.0 */
}

{
  'Timestamp' : ISODate("2017-01-01T00:01:00.000Z"),
  'Val' : 0.0 /* 1.0 - 1.0 */
}

{
  'Timestamp' : ISODate("2017-01-01T00:02:00.000Z"),
  'Val' : 2.0 /* 1.0 -  -1.0 */
}

{
  'Timestamp' : ISODate("2017-01-01T00:04:00.000Z"),
  'Val' : 3.0 /* -1.0 - (null) - 2.0 */
}

{
  'Timestamp' : ISODate("2017-01-01T00:05:00.000Z"),
  'Val' : 0.0 /* 2.0 - 2.0 */
}

{
  'Timestamp' : ISODate("2017-01-01T00:06:00.000Z"),
  'Val' : 1.0 /* 2.0 - 3.0 */
}

Hoffe esisteinigermaßenverständlich是ich meine