聚合查询
// aggregate里的各种查询可以组合使用
// 聚合查询
Entry.aggregate([ {
// $match 筛选,和find查询条件一致
$match: {
$or: [{'showcase.type': CONSTANT.contestType.STANDARD}],
'showcase.deleted': false,
contest: mongoose.Types.ObjectId(req.params.contestId) // 筛选id的话,需要使用object进行转换
// **需要和数据库中的字段类型一致 ObjectId parseInt...
}
},{
// $lookup 可以多次调用
$lookup: {
from: 'trainingDocuments', //要查询的表名字
localField: 'article', //在当前表(Entry)里的对应字段
foreignField: '_id', //trainingDocuments表里article对应的字段
as: 'articleDetail' //结果会在Entry表里添加一个articleDetail字段,内容是trainingDocuments表里查到的那条数据,新的articleDetail会被放在数组中,可以用$unwind拆开这个数组
}
}, {
// $unwind 拆开数组
$unwind: '$articleDetail' //如果articleDetail是数组,就会把数组拆开
}, {
$lookup: {
from: 'files',
localField: 'articleDetail.coverImage', //嵌套查询,使用嵌套查询条件'articleDetail.coverImage'时注意,要用$unwind把articleDetail拆开才能这样查询
foreignField: '_id',
as: 'articleDetail.coverImage'
}
}, {
$unwind: '$articleDetail.coverImage'
},{
// $sort 排序
$sort: {'createTime': -1} // 按指定字段排序
},{
// $limit 限制显示条数
$limit: parseInt(limit * page) // 限制显示条数,结合$skip可以做分页
},{
// $skip 查询跳过多少条数据
$skip: parseInt(limit * (page - 1)) // 每次跳过多少条数据
}{
// $group 分组做数据统计 擅长:按日期查询所有数据库中真实存在的数据统计; 不擅长:需要显示每周或者每天的数据(数据库中的数据 && 当天/月 为空为0的数据)数据统计
$group: {
_id: { // _id 查询条件
article: '$article',
name: '$name'
},
accessedTimes: {$sum: 1}, // $sum: 总共查询到几条数据
firstAccessed: {$first: '$created'}, // $first:查询到的集合中第一条数据的created字段值
lastAccessed: {$last: '$created'}, // $last:查询到的集合中最后一条数据的created字段值
lastLocation: {$last: '$position'}, // $last:查询到的集合中最后一条数据的position字段值
articleDetail: {$first: '$articleDetail'} // $first:查询到的集合中第一条数据的articleDetail字段值
}
}, {
$project: { // 指定要显示的字段
'articleDetail.title': 1,
'articleDetail.coverImage.smallURL': 1,
accessedTimes: 1,
firstAccessed: 1,
lastAccessed: 1,
lastLocation: 1
}
}], (err, entries) => {
// 查询之后回调
}
);
针对 group,经常有统计需求,按周统计每天的数据,但是当某天数据为空/零时便不会被 g r o u p , 经 常 有 统 计 需 求 , 按 周 统 计 每 天 的 数 据 , 但 是 当 某 天 数 据 为 空 / 零 时 便 不 会 被 group统计到,解决方案:
// 获得每周的起始时间
function _getWeeklyArray(startDate, endDate) {
let resArr = [];
let nextSunday = new Date(startDate.getTime() + ((7 - startDate.getDay()) * 24 * 60 * 60 * 1000));
resArr.push({
'weekStartTime': startDate,
'weekEndTime': nextSunday
});
while (new Date(nextSunday.getTime() + (7 * 24 * 60 * 60 * 1000)) < endDate) {
let lastSunday = new Date(nextSunday.getTime() + 24 * 60 * 60 * 1000);
nextSunday = new Date(nextSunday.getTime() + (7 * 24 * 60 * 60 * 1000));
resArr.push({
'weekStartTime': lastSunday,
'weekEndTime': nextSunday
});
}
//when nextSunday < endDate,add reset timezone.
if (nextSunday < endDate) {
nextSunday = new Date(nextSunday.getTime() + 24 * 60 * 60 * 1000);
resArr.push({
'weekStartTime': nextSunday,
'weekEndTime': endDate
});
}
return resArr;
}
// 开始统计
let created = new Date(req.user.created).toJSON().split('T')[0],
weekArray = driverInfoApiCtrl.getWeeklyArray(new Date(created.toString()), new Date());
Promise
.all(weekArray.map(weekDate => {
return Order
.aggregate([{
$match: {
created: {$gte: weekDate.weekStartTime, $lte: weekDate.weekEndTime}
}
}, {
$group: {
_id: {
year: {$year: '$created'},
yearMonthDay: {$dateToString: {format: "%Y-%m-%d", date: "$created"}}
},
trips: {$sum: 1},
earns: {$push: '$transactionInfo.driverReceive'}
}
}])
.then(orders => {
let formatOrders = [];
for (let i = new Date(weekDate.weekStartTime).getTime(); i <= new Date(weekDate.weekEndTime).getTime();) {
formatOrders.push({
_id: new Date(i).toJSON().split('T')[0],
trips: 0,
earns: '0.00'
});
i += 24 * 60 * 60 * 1000;
}
formatOrders.forEach(formatOrder => {
orders.forEach(order => {
if (formatOrder._id === order._id.yearMonthDay) {
formatOrder.trips = order.trips;
formatOrder.earns = _.sum(order.earns);
}
});
});
return Promise.resolve(formatOrders);
});
}))