首页 > 解决方案 > 在 MongoDB 聚合和 NodeJS 中计算过去 200 天的平均值

问题描述

我有一个脚本,它正在计算Volume我的 MongoDB 中每个集合的平均数据。但由于我有超过 1000 天的记录,我希望计算Average Volume过去 200 天的唯一记录。

目前我的脚本正在收集正在收集的全部数据(1000 天+)。

目标:我如何设置过去 200 天的范围来计算Volume它们的平均值。还有一件很重要的事,就是隔天我还想只用最后 200 天。

平均聚合框架

const saveToDatebase = async(symbol, BTCdata) => {
    try {
        const url = 'mongodb://username:passwprd@ipaddress/port?retryWrites=true&w=majority';
        let dateTime = getDateTime();
        let db = await MongoClient.connect(url, { useUnifiedTopology: true });
        const dbo = db.db('Crypto');
        const myobj = Object.assign({ Name: symbol, Date: dateTime }, BTCdata[0]);
        await dbo.collection(symbol).insertOne(myobj);
        const average = await dbo.collection(symbol).aggregate([{
            '$group': {
            _id:null,
                'Volume': {
                    '$avg': '$Volume'
                }
            }
        }]).toArray();
        console.log('1 document inserted');
        console.log(average);
        db.close();
    } catch (e) {
        console.error(e)
    }
};

EDIT1 像这样编辑代码后>>

const average = await dbo.collection(symbol).aggregate([{
    $match: {
        $gte: ["$dateTime", { $subtract: ["$$NOW", 200 * 60 * 60 * 24 * 1000] }]
    },
    "$group": {
        _id: null,
        "Volume": {
            "$avg": "$Volume"
        }
    }
}]).toArray();

我收到此错误 >MongoError: A pipeline stage specification object must contain exactly one field.

EDIT2 代码在获得如下代码后,我收到此错误 -MongoError: unknown top level operator: $gte

const average = await dbo.collection(symbol).aggregate([{
                $match: { $gte: ["$dateTime", { $subtract: ["$$NOW", 200 * 60 * 60 * 24 * 1000] }] }
            },
            {
                "$group": {
                    _id: null,
                    "Volume": {
                        "$avg": "$Volume"
                    }
                }
            }
        ])

这是文档在 MongoDB 中的样子。

在此处输入图像描述

EDIT3 这是我的代码关于最后一次改进的样子。代码是唯一的问题它没有返回我的平均水平。在我的终端中,我收到一个空数组[],但没有收到任何错误。我认为问题就在这里 -"$dateTime"我认为对它的查询是错误的。因为我也试图在 MongoDB Compass 中实现它。也不行。

代码在这里

  const average = await dbo.collection(symbol).aggregate([{
            $match: {
                $expr: {
                    $gte: [
                        "$dateTime",
                        {
                            $subtract: [
                                "$$NOW",
                                200 * 60 * 60 * 24 * 1000
                            ]
                        }
                    ]
                }
            }
        },
        {
            "$group": {
                _id: null,
                "Volume": {
                    "$avg": "$Volume"
                }
            }
        }
    ]).toArray();

编辑4

现在我收到一个空数组的唯一问题>[]我收到一个空数组,原因Date是保存为stringMongoDB,但要使聚合框架工作,我需要将其存储为object.

在下面的代码中,有我创建 Date 函数的方法,它将它保存在 MongoDB 中,因为string我可以更改它以将其保存为object

const getDateTime = () => {
    let today = new Date();
    let date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
    let time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
    return date + ' ' + time;
};

const saveToDatebase = async(symbol, BTCdata) => {
    try {
        const url = 'mongodb://username:password@ipadress/port?dbname?retryWrites=true&w=majority';
        let dateTime = getDateTime();
        let db = await MongoClient.connect(url, { useUnifiedTopology: true });
        const dbo = db.db('Crypto');
        const myobj = Object.assign({ Name: symbol, Date: dateTime }, BTCdata[0]);
        await dbo.collection(symbol).insertOne(myobj);
        const average = await dbo.collection(symbol).aggregate([{
                '$match': {
                    'dateTime': { '$gte': new Date((new Date().getTime() - (7 * 24 * 60 * 60 * 1000))) }
                },
            },
            {
                '$group': {
                    _id: null,
                    'Volume': { '$avg': '$Volume' }
                },
            }
        ]).toArray();
        console.log('1 document inserted');
        console.log(average);
        db.close();
    } catch (e) {
        console.error(e)
    }
};

来自 MongoDB 的文档作为文本:

    {
    "_id": {
        "$oid": "5f158c9d80d84408f6c38d8b"
    },
    "Name": "ADABTC",
    "Date": "2020-7-20 13:22:53",
    "Open": 0.0000133,
    "High": 0.0000133,
    "Low": 0.00001325,
    "Close": 0.00001326,
    "Volume": 1189734,
    "Timespan": 30
}

标签: javascriptnode.jsmongodb

解决方案


您必须在对文档进行分组之前对其进行过滤。应该是这样的:

db.collection.aggregate([
   {
      $addFields: {
         DateObj: {
            $regexFindAll: { input: "$Date", regex: "\\d+" }
         }
      }
   },
   {
      $set: {
         DateObj: {
            $dateFromParts: {
               year: { $toInt: { $arrayElemAt: ["$DateObj.match", 0] } },
               month: { $toInt: { $arrayElemAt: ["$DateObj.match", 1] } },
               day: { $toInt: { $arrayElemAt: ["$DateObj.match", 2] } },
               hour: { $toInt: { $arrayElemAt: ["$DateObj.match", 3] } },
               minute: { $toInt: { $arrayElemAt: ["$DateObj.match", 4] } },
               second: { $toInt: { $arrayElemAt: ["$DateObj.match", 5] } },
               timezone: "Europe/Zurich"
            }
         }
      }
   },
   {
      $match: {
         $expr: {
            $gte: ["$DateObj", { $subtract: ["$$NOW", 200 * 60 * 60 * 24 * 1000] }]
         }
      }
   },
   {
      "$group": {
         _id: null,
         "Volume": {
            "$avg": "$Volume"
         }
      }
   }
])

推荐阅读