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

6 回复

要在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);

解释

  1. 连接到MongoDB:首先连接到MongoDB数据库。
  2. 定义时间范围:定义今天的开始时间、本周的开始时间、本月的开始时间和本年的开始时间。
  3. 聚合管道:使用多个聚合阶段来过滤和分组数据,计算每个时间段的amount总和。
  4. 输出结果:将结果打印出来。

通过这种方式,你可以一次性计算出不同时间段的总和。


上周刚看了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求和。以下是如何构建这样的查询的步骤和示例代码。

步骤说明

  1. 筛选日期范围:根据不同的时间段(如今天、本周、本月、本年)筛选出符合条件的数据。
  2. 计算总和:使用聚合管道中的$group阶段对筛选后的数据进行求和操作。
  3. 结果输出:将每个时间段的总和组织成预期的格式。

示例代码

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阶段,并调整日期范围以适应所需的时间段。

这样,你就可以得到指定时间段内的总和了。希望这对你有所帮助!

回到顶部