在Mongo Shell中计算简单移动平均线

时间:2018-08-18 07:33:09

标签: mongodb mongodb-query aggregation-framework

我正在使用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'}]

2 个答案:

答案 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,只需在分配第一个值之前对其进行检查。