首页 文章

GroupBy MongoDB中的多个列

提问于
浏览
1

我有一个 shifts 集合,如下所示

{
    "_id" : ObjectId("5885a1108c2fc432d649647d"),
    "from" : ISODate("2017-01-24T06:21:00.000Z"), //can be weekday, sat, sun
    "to" : ISODate("2017-01-24T08:21:00.000Z"),
    "jobId" : ObjectId("586d7d6acfc7e05669d6e2c8"),
    "hourlyRate" : 32 //this wil vary based on **from** field
}

{
    "_id" : ObjectId("5885a1108c2fc432d649647e"),
    "from" : ISODate("2017-01-25T06:21:00.000Z"),
    "to" : ISODate("2017-01-25T08:21:00.000Z"),
    "jobId" : ObjectId("586d7d6acfc7e05669d6e2c8"),
    "hourlyRate" : 32
}

{
    "_id" : ObjectId("5885a1108c2fc432d649647f"),
    "from" : ISODate("2017-01-26T06:21:00.000Z"),
    "to" : ISODate("2017-01-26T08:21:00.000Z"),
    "jobId" : ObjectId("586d7d6acfc7e05669d6e2c8"),
    "hourlyRate" : 32
}

我希望能够生成这样的输出

作业A(这可以使用jobId获得)

  • 平日收入 - 50美元(2 * 25美元)

  • 周六收入 - $ 90(3 * $ 30)

  • 周日收入 - 100美元(2 * 50美元)总收入= 240美元

工作B.

  • 平日收入..............

总收入=工作A工作B ..... = $ X.

工作日或周六或周日可以从 from 字段派生 . 对于工作日,需要对周一至周五的所有日期进行分组 . 通过从 to 中减去 from 可以得出小时数 .

所以,我认为需要完成以下工作,但我无法在MongoDB中实现

  • 分组 jobId ,从 from 中提取的每日分组(也是所有工作日的分组),并通过减去 fromto 获得提取的小时数 .

  • 最后,获得上述所有金额的总和以获得总收入

  • 获取所有工作收入的最终总和 .

我发现了一些类似的问题,但我无法将其应用于我的情况
mongodb group values by multiple fields
Mongodb Aggregation Framework | Group over multiple values?
How to group by multiple columns and multiple values in mongodb

使用案例:
当用户访问名为“收入”的页面时,我需要向他显示每个作业和总收入的上周收入(然后他可以更改日期范围) . 因此,我打算将节目分成每个工作,进一步分为工作日,周六和周日收入以及该工作的总收入和工作时间 . 最终总收入是所有个人工作收入的总和 .

P.S我正在使用MongoDB 3.4

2 回答

  • 0

    请遵循以下聚合查询:

    db.shifts.aggregate([{ 
        //this get the day of week and converts them into sunday, saturday
        $project: {
            jobId:1,
            hourlyRate:1, 
            dayOfWeek: { $dayOfWeek: "$from" }, 
            workedHours: {$divide:[{ $subtract: ["$to", "$from"] }, 3600000]}, 
            saturday:{$floor: {$divide:[{ $dayOfWeek: "$from" }, 7]}},
            sunday:{$floor: {$divide:[{$abs:{$subtract:[{ $dayOfWeek: "$from" }, 7]}}, 6]}},
        }
    }, {
        //based on the values of sunday and saturday gets the value of weekday
        $project: {
            jobId:1,
            workedHours:1,
            hourlyRate:1,
            saturday:1,
            sunday: 1,
            weekday:{$abs: {$add:["$sunday","$saturday", -1]}},
        } 
    }, {
        //here calculates the earnings for each job
        $group:{
            _id:"$jobId",
            sundayEarnings:{$sum: {$multiply:["$sunday", "$hourlyRate", "$workedHours"]}},
            saturdayEarnings:{$sum: {$multiply:["$saturday", "$hourlyRate", "$workedHours"]}},
            weekdayEarnings:{$sum: {$multiply:["$weekday", "$hourlyRate", "$workedHours"]}},
            totalEarnings: {$sum:{$multiply:["$hourlyRate", "$workedHours"]}},
            totalWorkedHours: {$sum: "$workedHours"}
        }
    }, {
        //and finally calculates the total jobs earnings
        $group:{
            _id:null,
            jobs:{$push:{
                jobId: "$_id",
                sundayEarnings: "$sundayEarnings",
                saturdayEarnings: "$saturdayEarnings",
                weekdayEarnings: "$weekdayEarnings",
                totalEarnings: "$totalEarnings",
                totalWorkedHours: "$totalWorkedHours"
            }},
            totalJobsEarning: {$sum: "$totalEarnings"}
        }
    }])
    
    • 第一个 $project 聚合通过进行多次算术计算,根据 dayOfWeek 值为 saturdaysunday 提供 0 or 1 值 .

    • 第二个 $project 聚合根据 saturdaysunday 值计算 weekday 的值 .

    • 第一个 $group 计算每个工作中每天的收入 .

    • 最后,第二个 $group 聚合计算所有工作的收入总和 .

    Test

    这是我的意见:

    {
        "_id" : ObjectId("5885a1108c2fc432d649647d"),
        "from" : ISODate("2017-01-24T06:21:00Z"),
        "to" : ISODate("2017-01-24T08:21:00Z"),
        "jobId" : ObjectId("586d7d6acfc7e05669d6e2c8"),
        "hourlyRate" : 32
    }
    {
        "_id" : ObjectId("5885a1108c2fc432d649647e"),
        "from" : ISODate("2017-01-25T06:21:00Z"),
        "to" : ISODate("2017-01-25T08:21:00Z"),
        "jobId" : ObjectId("586d7d6acfc7e05669d6e2c8"),
        "hourlyRate" : 32
    }
    {
        "_id" : ObjectId("5885a1108c2fc432d649647f"),
        "from" : ISODate("2017-01-26T06:21:00Z"),
        "to" : ISODate("2017-01-26T08:21:00Z"),
        "jobId" : ObjectId("586d7d6acfc7e05669d6e2c8"),
        "hourlyRate" : 32
    }
    {
        "_id" : ObjectId("58870cfd59dfb6b0c4eadd72"),
        "from" : ISODate("2017-01-28T06:21:00Z"),
        "to" : ISODate("2017-01-28T08:21:00Z"),
        "jobId" : ObjectId("586d7d6acfc7e05669d6e2c8"),
        "hourlyRate" : 32
    }
    {
        "_id" : ObjectId("58870dc659dfb6b0c4eadd73"),
        "from" : ISODate("2017-01-29T06:21:00Z"),
        "to" : ISODate("2017-01-29T08:21:00Z"),
        "jobId" : ObjectId("586d7d6acfc7e05669d6e2c8"),
        "hourlyRate" : 32
    }
    

    上面的聚合查询给出以下输出:

    {
        "_id" : null,
        "jobs" : [
            {
                "jobId" : ObjectId("586d7d6acfc7e05669d6e2c8"),
                "sundayEarnings" : 64,
                "saturdayEarnings" : 64,
                "weekdayEarnings" : 192,
                "totalEarnings" : 320,
                "totalWorkedHours" : 10 
            }
        ],
        "totalJobsEarning" : 320
    }
    

    jobs 数组中只有一个作业,因为shift集合的文档引用了相同的 jobId . 您可以尝试使用不同的 jobId ,它会为您提供不同的工作总收入 .

  • 1

    使用 $switch 运算符构建case语句的表达式来评估收益,您可以运行以下管道以获得所需的结果

    var hoursWorked = { 
        "$divide": [
            { "$subtract": ["$to", "$from"] }, 
            3600000
        ]
    };
    
    db.collection('shifts').aggregate([
        {
            "$match": {
                "jobId": { "$in": [jobA_id, jobB_id] },
                "from": { "$gte": new Date() }
            }
        },
        {
            "$group": {
                "_id": null,
                "totalEarnings": {
                    "$sum": {
                        "$switch": {
                            "branches": [
                                {
                                    "case": { 
                                        "$not": { 
                                            "$in": [
                                                { "$dayOfWeek": "$from" }, 
                                                [1, 7] 
                                            ] 
                                        } 
                                    }, 
                                    "then": { "$multiply": [hoursWorked, 20] }
                                },
                                { 
                                    "case": { 
                                        "$eq": [
                                            { "$dayOfWeek": "$from" }, 
                                            7
                                        ] 
                                    }, 
                                    "then": { "$multiply": [hoursWorked, 25] }
                                },
                                { 
                                    "case": { 
                                        "$eq": [
                                            { "$dayOfWeek": "$from" }, 
                                            1 
                                        ] 
                                    }, 
                                    "then": { "$multiply": [hoursWorked, 30] } 
                                }
                            ]
                            "default": 0
                        }   
                    } 
                }              
            }
        }       
    ], function(err, results) {
        if (err) throw err;
        console.log(JSON.stringify(results, null, 4));
        console.log(results[0].totalEarnings); 
    });
    

相关问题