NodeJS - 通过URL模式构建与日期相关的Mongoose查询

时间:2017-05-07 19:55:18

标签: node.js mongodb mongoose

我正在构建一个节点和mongo / mongoose应用程序,它允许我导入然后通过URL模式“查询”银行对帐单。

我的声明模型看起来像

man malloc

当我运行像var mongoose = require('mongoose'); var Schema = mongoose.Schema; var statementSchema = new Schema({ date: { type: Date, required: true }, name: { type: String, required: true }, method: { type: String }, amount: { type: Number, required: true }, category: { type: String, default: 'Not Set' }, importDate: { type: Date, default: Date.now, required: true } }); statementSchema.index({ "date":1, "name":1, "amount":1 }, { unique: true }); module.exports = mongoose.model('Statement', statementSchema);

这样的mongo查询时

我收到的许多文件看起来像是:

db.statements.find({ "name": "RINGGO" })

我想构建应用程序,以便:

  • { "_id" : ObjectId("5907a2850780a44f671707f5"), "amount" : -6.3, "name" : "RINGGO", "method" : "VIS", "date" : ISODate("2017-03-23T00:00:00Z"), "importDate" : ISODate("2017-05-01T21:03:01.770Z"), "category" : "Not Set", "__v" : 0 } 返回该供应商的所有交易和总支出
  • domain.com/:vendor返回2017年该供应商的所有交易以及2017年的总支出
  • domain.com/:vendor/2017返回2017年1月该供应商的所有交易以及2017年1月的总支出
  • domain.com/:vendor/2017/January返回该供应商在2017年1月第1周的所有交易以及2017年1月1日的总支出

目前我有一条路线(将数据传递给Handlebars)获得所有花费(但不是总数)

domain.com/:vendor/2017/January/wk01

有关如何构建必要查询的任何建议都会很棒。我一直在阅读(和练习)mongo聚合,但我并没有真正接近我想要的。我希望能够使用该结构来构建URL模式domain.com/:category,domain.com/:category/2017等

对不起,我已经生病了(现在还是),因为我发布了这个问题,所以我没有时间去做很多工作,但我确实根据@ profesor79的回答得到了一点点这个问题How to aggregate data by each day, week, month wise in corresponding week, month, year respectively in mongodb

我可以在mongo shell中执行以下内容

router.get('/:vendor?', function (req, res, next) {

var vendorName = req.params.vendor;
Statement.find({ name: req.params.vendor }, function (err, doc) {
    if (err) {
        console.error('error no entries found');
    }
    res.render('vendor', {
        vendor: vendorName,
        shop: doc
    });
});

并取回结果

db.statements.aggregate([{
    $project : {
        year : {
            $year : "$date"
        },
        month : {
            $month : "$date"
        },
        week : {
            $week : "$date"
        },
        day : {
            $dayOfWeek : "$date"
        },
        _id : 1,
        name : 1,
        amount:1
    }
},
{
           $group : {
               _id : {
                   year : "$year",
                   month : "$month",
                   week : "$week",
                   day : "$day"
               },
               totalDailyAmount : {
                   $sum : "$amount"
               }
           }
       },
{
    $group : {

        _id : {
            year : "$_id.year",
            month : "$_id.month",
            week : "$_id.week"
        },
        totalWeeklyAmount : {
            $sum : "$totalDailyAmount"
        },
        totalDayAmount : {
            $push : {
                totalDayAmount : "$totalDailyAmount",
                dayOfWeek : "$_id.day"
            }
        }
    }
}, {
    $match : {
        "_id.month" : 3,
        "_id.week" : 12
    }
}
]
)

然而1)我无法弄清楚如何获得支出的月度和年度总数(与第二次{ "_id" : { "year" : 2017, "month" : 3, "week" : 12 }, "totalWeeklyAmount" : 2870.5099999999998, "totalDayAmount" : [ { "totalDayAmount" : -40, "dayOfWeek" : 1 }, { "totalDayAmount" : 3366.35, "dayOfWeek" : 6 }, { "totalDayAmount" : -185.27, "dayOfWeek" : 2 }, { "totalDayAmount" : -29.8, "dayOfWeek" : 3 }, { "totalDayAmount" : -58.5, "dayOfWeek" : 5 }, { "totalDayAmount" : -132.27, "dayOfWeek" : 4 }, { "totalDayAmount" : -50, "dayOfWeek" : 7 } ] } totalDayAmount的处理方式相同

2)我不能将此限制为仅限特定供应商的交易。我试过了

group

但名字不在结果中。

我认为以下可能有用

{
    $match : {
        "_id.month" : 3,
        "_id.week" : 12,
        "name": "vendor-name"
    }

1 个答案:

答案 0 :(得分:0)

  1. 网址格式
  2. 使用查询参数代替params通常是一个好主意,因为它很容易扩展,顺序无关紧要。在您的情况下,它应该是:domain.com/?vendor=RINGGO&year=2017&month=January&week=1。稍后您可以使用&category=something扩展它。

    1. 查询
    2. 由于您的查询依赖于日期操作,我建议使用momentnpm install moment --save来简化任务。

      假设您遵循上面的网址格式,则查询应为:

      var startTime;
      var endTime;
      var year = req.query.year;
      var month = req.query.month? moment().month(req.query.month).format("M") : null; // January to 1
      var week = parseInt(req.query.week);
      var query = {
          name : req.query.vendor  // assuming only vendor is required
      };
      
      if(year && month && week){ //if all available
          //week-1 to week is the week of this month we need e.g. week 2 of January is 2017-01-08 & 2017-01-15 respectively
          startTime = new Date(moment([year, month -1]).startOf('month').add(week-1, 'weeks')); // month -1 because JS month starts from 0
          endTime = new Date(moment([year, month -1]).startOf('month').add(week, 'weeks'));
      }
      else if(year && month){ //if week unavailable
          //if January 2017 then 2016-12-31 & 2017-01-31 respectively
          startTime = new Date(moment([year, month -1]).endOf('month').subtract(1, "month"));
          endTime = new Date(moment([year, month -1]).endOf('month'));
      }
      else if(year){ // only year available
          //if 2017 then 2016-12-31 & 2017-12-31 respectively
          startTime = new Date(moment([year]).endOf('year').subtract(1, "year"));
          endTime = new Date(moment([year]).endOf('year'));
      }
      
      //add time to query if available
      startTime && endTime ? query.date = {$gt: startTime, $lt: endTime}: null;
      
      Statement.aggregate([
          {
              $match : query
          },
          {
               $group : {
                 _id : "$name",  statements: { $push: "$$ROOT" }, //$$ROOT adds all the documents processed in grouping
                 totalSpend: { $sum: "$amount" }
              }
          }
      ], function(err, statements){
          if(err){
              console.log(err)
          }
          else{
              console.log(statements)
          }
      })
      

      模拟domain.com/?vendor=RINGGO&year=2017&month=January&week=4,这是我的虚拟db文档的测试结果。

      [
          {
              "_id": "RINGGO",
              "statements": [
                  {
                      "_id": "5907a2850780a44f671707f1",
                      "amount": 10,
                      "name": "RINGGO",
                      "method": "VIS",
                      "date": "2017-01-23T00:00:00.000Z",
                      "importDate": "2017-01-01T21:03:01.770Z",
                      "category": "Not Set",
                      "__v": 0
                  },
                  {
                      "_id": "5907a2850880a44f671707f1",
                      "amount": 10,
                      "name": "RINGGO",
                      "method": "VIS",
                      "date": "2017-01-24T00:00:00.000Z",
                      "importDate": "2017-01-01T21:03:01.770Z",
                      "category": "Not Set",
                      "__v": 0
                  }
              ],
              "totalSpend": 20
          }
      ]