我正在构建一个节点和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);
我收到的许多文件看起来像是:
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"
}
答案 0 :(得分:0)
使用查询参数代替params通常是一个好主意,因为它很容易扩展,顺序无关紧要。在您的情况下,它应该是:domain.com/?vendor=RINGGO&year=2017&month=January&week=1
。稍后您可以使用&category=something
扩展它。
由于您的查询依赖于日期操作,我建议使用moment:npm 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
}
]