Nodejs中mongodb的arggregate如何做sum,求mongodb高手
Nodejs中mongodb的arggregate如何做sum,求mongodb高手
数据结构如下: { _id: ObjectId, items: [ {amount: Number, date: Date} ] }
现在要统计指定_id下,items.date在某个时间范围内的amount总和,并且我想用一条语句统计多个时间段的总和,期望的结果大致是:
今天:100 本周:9482 本月:11930 本年:1403820
要在Node.js中使用MongoDB的聚合框架来计算特定时间段内的amount
总和,可以利用聚合管道(aggregation pipeline)中的多个阶段来实现。以下是一个示例代码,展示如何根据不同的时间范围(如今天、本周、本月、本年)来计算amount
的总和。
首先确保你已经安装了mongoose
或者直接使用mongodb
驱动包来连接MongoDB数据库。
示例代码
const { MongoClient } = require('mongodb');
async function calculateAmounts() {
const uri = "your_mongodb_connection_string";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
try {
await client.connect();
const database = client.db('your_database_name');
const collection = database.collection('your_collection_name');
// 获取当前时间和日期
const now = new Date();
const yearStart = new Date(now.getFullYear(), 0, 1);
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
const weekStart = new Date(now.getFullYear(), now.getMonth(), now.getDate() - now.getDay());
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const result = await collection.aggregate([
{
$match: {
_id: ObjectId("your_object_id"),
items: {
$elemMatch: {
date: {
$gte: todayStart,
$lt: new Date(todayStart.getTime() + 24 * 60 * 60 * 1000)
}
}
}
}
},
{
$unwind: "$items"
},
{
$match: {
"items.date": {
$gte: todayStart,
$lt: new Date(todayStart.getTime() + 24 * 60 * 60 * 1000)
}
}
},
{
$group: {
_id: null,
todayTotal: { $sum: "$items.amount" }
}
},
{
$facet: {
today: [
{
$match: {
"items.date": {
$gte: todayStart,
$lt: new Date(todayStart.getTime() + 24 * 60 * 60 * 1000)
}
}
},
{
$group: {
_id: null,
todayTotal: { $sum: "$items.amount" }
}
}
],
thisWeek: [
{
$match: {
"items.date": {
$gte: weekStart,
$lt: new Date(weekStart.getTime() + 7 * 24 * 60 * 60 * 1000)
}
}
},
{
$group: {
_id: null,
thisWeekTotal: { $sum: "$items.amount" }
}
}
],
thisMonth: [
{
$match: {
"items.date": {
$gte: monthStart,
$lt: new Date(monthStart.getTime() + 31 * 24 * 60 * 60 * 1000)
}
}
},
{
$group: {
_id: null,
thisMonthTotal: { $sum: "$items.amount" }
}
}
],
thisYear: [
{
$match: {
"items.date": {
$gte: yearStart,
$lt: new Date(yearStart.getTime() + 365 * 24 * 60 * 60 * 1000)
}
}
},
{
$group: {
_id: null,
thisYearTotal: { $sum: "$items.amount" }
}
}
]
}
},
{
$project: {
todayTotal: { $arrayElemAt: ["$today.todayTotal", 0] },
thisWeekTotal: { $arrayElemAt: ["$thisWeek.thisWeekTotal", 0] },
thisMonthTotal: { $arrayElemAt: ["$thisMonth.thisMonthTotal", 0] },
thisYearTotal: { $arrayElemAt: ["$thisYear.thisYearTotal", 0] }
}
}
]).toArray();
console.log(result[0]);
} finally {
await client.close();
}
}
calculateAmounts().catch(console.error);
解释
- 连接到MongoDB:首先连接到MongoDB数据库。
- 定义时间范围:定义今天的开始时间、本周的开始时间、本月的开始时间和本年的开始时间。
- 聚合管道:使用多个聚合阶段来过滤和分组数据,计算每个时间段的
amount
总和。 - 输出结果:将结果打印出来。
通过这种方式,你可以一次性计算出不同时间段的总和。
上周刚看了aggregate, 好像先用 projection 把数组打开,再加起来。
是用 $unwind
数据如下:
/* 0 */ { "_id" : ObjectId(“51a9e1d168590303d0b1038f”), “items” : [{ “amount” : 10 }] }
/* 1 */ { "_id" : ObjectId(“51a9e1fa68590303d0b10390”), “items” : [{ “amount” : 20 }, { “amount” : 15 }, { “amount” : 30 }] }
/* 2 */ { "_id" : ObjectId(“51a9e20c68590303d0b10391”), “items” : [{ “amount” : 11 }, { “amount” : 12 }, { “amount” : 16 }] }
db.product.aggregate( { $unwind: “$items” }, { $project: { _id:0, amount: “$items.amount”} }, { $group: { _id:null, count: {$sum:"$amount"} } }) { “result” : [ { “_id” : null, “count” : 114 } ], “ok” : 1 }
结果是 114
$unwind 把数组打开
$project 选择变量,给变量改名
$group 组合,做数学运算
为了实现你的需求,可以使用MongoDB的聚合框架(aggregation framework)来完成对不同时间段内的amount
求和。以下是如何构建这样的查询的步骤和示例代码。
步骤说明
- 筛选日期范围:根据不同的时间段(如今天、本周、本月、本年)筛选出符合条件的数据。
- 计算总和:使用聚合管道中的
$group
阶段对筛选后的数据进行求和操作。 - 结果输出:将每个时间段的总和组织成预期的格式。
示例代码
const mongoose = require('mongoose');
const { ObjectId } = mongoose.Types;
// 假设我们已经有了一个名为 'yourCollection' 的集合连接
const collection = yourDatabase.collection('yourCollection');
const today = new Date();
const thisWeekStart = new Date();
thisWeekStart.setDate(today.getDate() - today.getDay());
const thisMonthStart = new Date(today.getFullYear(), today.getMonth(), 1);
const thisYearStart = new Date(today.getFullYear(), 0, 1);
collection.aggregate([
// 过滤 _id
{ $match: { _id: new ObjectId('指定的_id') } },
// 筛选今天的记录
{ $match: { 'items.date': { $gte: today, $lt: new Date(today.setHours(24)) } } },
{
$project: {
items: {
$filter: {
input: '$items',
as: 'item',
cond: { $and: [{ $gte: ['$$item.date', today] }, { $lt: ['$$item.date', new Date(today.setHours(24))] }] }
}
}
}
},
// 计算今天的总和
{
$addFields: {
totalToday: { $sum: '$items.amount' }
}
},
// 类似地,处理本周、本月和本年的逻辑
// 注意这里只是展示今天的逻辑,其余逻辑可以类推
]).toArray((err, result) => {
if (err) throw err;
console.log(result); // 输出结果
});
解释
- $match: 首先过滤出指定的
_id
,然后进一步过滤日期。 - $filter: 在
items
数组中过滤出满足条件的元素。 - $sum: 对满足条件的
amount
字段值进行求和。
对于其他时间段(如本周、本月、本年),需要类似地添加额外的$match
和$filter
阶段,并调整日期范围以适应所需的时间段。
这样,你就可以得到指定时间段内的总和了。希望这对你有所帮助!