我有一个脚本,用于计算MongoDB中每个集合的平均Volume
数据。但是由于记录的时间已经超过1000天,所以我只想计算最近200天的Average Volume
。
目前,我的脚本正在收集收集中的所有数据(超过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();
EDIT4
现在唯一的问题是我收到一个空数组> []
我收到一个空数组,原因是Date
被另存为string
到MongoDB,但是要使聚合框架正常工作,我需要将其存储为object
。
在下面的代码中,我有一种创建Date函数的方法,它将它以string
的形式保存在MongoDB中如何更改它以将其另存为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
}
答案 0 :(得分:1)
在对文档进行分组之前,必须先对其进行过滤。应该是这样的:
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"
}
}
}
])