我正在使用Nodejs开发金融应用程序。我想知道是否有可能直接计算出简单的移动平均线,即直接在Mongo Shell中最近N天的价格,而不是在Node js中读取和计算价格。
文档样本。
[{code:'0001',price:0.10,date:'2014-07-04T00:00:00.000Z'},
{code:'0001',price:0.12,date:'2014-07-05T00:00:00.000Z'},{code:'0001',price:0.13,date:'2014-07-06T00:00:00.000Z'},
{code:'0001',price:0.12,date:'2014-07-07T00:00:00.000Z'}]
答案 0 :(得分:2)
如果文档数量不多,则应该使用DB服务器而不是JS来完成工作。
您没有说是直接使用猫鼬还是直接使用节点驱动程序。我假设您正在使用猫鼬,因为这是大多数人的生活习惯。
因此您的模型将是:
// models/stocks.js
const mongoose = require("mongoose");
const conn = mongoose.createConnection('mongodb://localhost/stocksdb');
const StockSchema = new mongoose.Schema(
{
price: Number,
code: String,
date: Date,
},
{ timestamps: true }
);
module.exports = conn.model("Stock", StockSchema, "stocks");
您正确地建议聚合框架是进入此处的好方法。首先,如果我们要处理日期范围之间的返回值,则数据库中的记录必须是日期对象。从示例文档中,您可能已经放入了字符串。使用日期插入对象的示例为:
db.stocks.insertMany([{code:'0001',price:0.10,date:ISODate('2014-07-04T00:00:00.000Z')}, {code:'0001',price:0.12,date:ISODate('2014-07-05T00:00:00.000Z')},{code:'0001',price:0.13,date:ISODate('2014-07-06T00:00:00.000Z')}, {code:'0001',price:0.12,date:ISODate('2014-07-07T00:00:00.000Z')}])
aggregation pipeline函数接受具有一个或多个管道阶段的数组。
我们应该使用的第一个流水线阶段是$match
,$match docs,这会将文档过滤为仅对我们感兴趣的记录,这对性能很重要
{ $match: {
date: {
$gte: new Date('2014-07-03'),
$lte: new Date('2014-07-07')
}
}
}
此阶段仅将2014年7月3日至7日(含)的文档发送到下一阶段(在本例中为所有示例文档)
下一阶段是您可以获取平均水平的阶段。我们需要根据一个字段,多个字段或所有字段将值分组在一起。
由于您未指定要平均的字段,因此我将为所有字段提供示例。为此,我们使用$group
对象$group docs
{
$group: {
_id: null,
average: {
$avg: '$price'
}
}
}
这将获取所有单据并显示所有价格的平均值。
对于您的示例文档,结果为
{ _id: null, avg: 0.1175 }
检查答案:
(0.10 + 0.12 + 0.12 + 0.13) / 4 = 0.1175
仅供参考:我不会依赖javascript进行的计算(例如使用浮点数的数字)的任何关键操作。如果您对此感到担心,请参阅https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html以获取更多详细信息。
为完整起见,这里是完整的聚合查询
const Stock = require("./models/stocks");
Stock.aggregate([{ $match: {
date: {
$gte: new Date('2014-07-03'),
$lte: new Date('2014-07-07')
}
}},
{
$group: {
_id: null,
avg: {
$avg: '$price'
}
}
}])
.then(console.log)
.catch(error => console.error(error))
答案 1 :(得分:0)
不确定您的移动平均线公式,但是这是我的方法:
onload
输出:
var moving_average = null
db.test.find().forEach(function(doc) {
if (moving_average==null) {
moving_average = doc.price;
}
else {
moving_average = (moving_average+doc.price)/2;
}
})
如果您想定义要计算平均值的N天,只需修改查找的参数即可:
> moving_average
0.3
如果要单行执行上述shell代码,则可以假定未定义Moving_average,只需在分配第一个值之前对其进行检查。