数据库聚合操作

db.command.aggregate

920 发布: 2024/9/5 09:12 本文总阅读量

示例1

async list() {
    const $ = db.command.aggregate
    let res = await db.collection("dcloud-inc").aggregate()
        .group({
            // 按照 date 字段进行分组
            _id: "$date",
            // 对 inctype=0 的数据中的 money 进行求和计算,并将所求之和作为 normoney 输出
            normoney: {
                $sum: {
                    $cond: {
                        if: { $eq: ["$inctype", 0] },
                        then: "$money",
                        else: 0
                    }
                }
            },
            // 对 inctype=1 的数据中的 money 进行求和计算,并将所求之和作为 extmoney 输出
            extmoney: {
                $sum: {
                    $cond: {
                        if: { $eq: ["$inctype", 1] },
                        then: "$money",
                        else: 0
                    }
                }
            },
            /*
             * 对同一 date 下的所有 mark 合并处理;
             * 处理方式:
             * 对每条数据的 mark 做非空判断,不为空就将此条 mark+分号,加入到 allmark
             * 为空就将空字符串加入到 allmark
             * 
             * 注意:
             * 这时输出的 allmark 是一个数组,
             * 对非空 mark 拼接分号是为了下一步处理成字符串做准备
             */
            allmark: {
                $addToSet: {
                    $cond: {
                        if: { $ne: ["$mark", ""] },
                        then: { $concat: ["$mark", ";"] },
                        else: ""
                    }
                }
            }
        })
        .addFields({
            /*
             * allmark 字段可能是一个包含多个字符串的数组。
             * $reduce 是一个聚合操作符,它会遍历数组中的每个元素并根据定义的逻辑来处理这些元素。
             * 在这里,input: "$allmark" 指定了要处理的数组,即 allmark 字段中的值。
             * initialValue: "" 表示初始值为空字符串,它是 $reduce 操作的初始累加器的值。
             * in: { $concat: ["$$value", "$$this"] } 定义了在每次迭代中如何处理元素。
             * $$value 表示当前的累加器值;
             * $$this 表示当前处理的元素.在这里,每次迭代都将当前元素连接到累加器值后面。
             */
            allmark: {
                $reduce: {
                    input: "$allmark",
                    initialValue: "",
                    in: { $concat: ["$$value", "$$this"] }
                }
            }
        })
        /*
         * 在当前集合和 'dcloud-works' 集合之间建立一个关联,
         * 根据当前集合中的 _id 字段与 'dcloud-works' 集合中的 date 字段进行匹配,
         * 并将匹配的结果作为一个数组存储在名为 'works' 的新字段中.
         *
         * 注意:
         * 这时输出的 works 是一个数组. 
         */
        .lookup({
            from: 'dcloud-works',
            // 当前集合的字段
            localField: '_id',
            // 关联表中的字段
            foreignField: 'date',
            // 关联结果存储在 works 中输出
            as: 'works',
        })
        .addFields({
            /**
             * 这段代码的作用是将字段 works 处理为一个对象。
             * 如果 works 是一个空数组,则将 works 设置为一个空对象。
             * 如果 works 不是一个空数组,则将 works 数组中的第一个元素输出
             */
            works: {
                $cond: {
                    if: {
                        // 判断数组的长度是否为0
                        $eq: [ {$size: "$works"}, 0]
                    },
                    then: {},
                    else: { $arrayElemAt: ["$works", 0] }
                }
            }
        })
        .sort({
            _id: -1
        })
        .end()

    console.log("rk===>[res]", res);

    return {
        errSubject: '',
        errCode: 0,
        errMsg: 'ok'
    }
}

结果1

{
    "affectedDocs": 2,
    "data": [
        {
            "_id": "2024-09",
            "normoney": 500000,
            "extmoney": 0,
            "allmark": "",
            "works": {
                "_id": "66d812adf2949ce0c74562ab",
                "year": "2024",
                "date": "2024-09",
                "isfull": 1,
                "fullday": 30,
                "eventhour": 0,
                "create_time": 1725436589212,
                "update_time": 1725436589212
            }
        },
        {
            "_id": "2024-08",
            "normoney": 550000,
            "extmoney": 120000,
            "allmark": "111;",
            "works": {

            }
        }
    ]
}

示例2

async list() {
    const $ = db.command.aggregate
    let res = await db.collection("dcloud-inc").aggregate()
        .group({
            // 同示例1区别
            _id: {year:"$year",date:"$date"},
            normoney: {
                $sum: {
                    $cond: {
                        if: { $eq: ["$inctype", 0] },
                        then: "$money",
                        else: 0
                    }
                }
            },
            extmoney: {
                $sum: {
                    $cond: {
                        if: { $eq: ["$inctype", 1] },
                        then: "$money",
                        else: 0
                    }
                }
            },
            allmark: {
                $addToSet: {
                    $cond: {
                        if: { $ne: ["$mark", ""] },
                        then: { $concat: ["$mark", ";"] },
                        else: ""
                    }
                }
            }
        })
        .addFields({
            // 同示例1区别
            normoney: { $divide: ["$normoney", 100] },
            extmoney: { $divide: ["$extmoney", 100] },
            allmark: {
                $reduce: {
                    input: "$allmark",
                    initialValue: "",
                    in: { $concat: ["$$value", "$$this"] }
                }
            }
        })
        .lookup({
            from: 'dcloud-works',
            // 同示例1区别
            localField: '_id.date',
            foreignField: 'date',
            as: 'works',
        })
        .addFields({
            works: {
                $cond: {
                    if: { $eq:[ {$size: "$works"}, 0] },
                    then: {},
                    else: { $arrayElemAt: ["$works", 0] }
                }
            }
        })
        .sort({
            _id: -1
        })
        // 同示例1区别
        .group({
            _id:"$_id.year",
            normoney: { $sum: "$normoney" },
            extmoney: { $sum: "$extmoney" },
            data:{$push:"$$ROOT"}
        })
        // 同示例1区别
        .addFields({
            total:{ $sum: ["$normoney", "$extmoney"] }
        })
        .sort({
            _id: -1
        })
        .end()

    console.log("rk===>[res]", res);

    return {
        errSubject: '',
        errCode: 0,
        errMsg: 'ok',
        data:res.data,
    }
}

结果2

{
    "affectedDocs": 1,
    "data": [
        {
            "_id": "2024",
            "normoney": 10500,
            "extmoney": 1200,
            "data": [
                {
                    "_id": {
                        "year": "2024",
                        "date": "2024-09"
                    },
                    "normoney": 5000,
                    "extmoney": 0,
                    "allmark": "",
                    "works": {
                        "_id": "66d812adf2949ce0c74562ab",
                        "year": "2024",
                        "date": "2024-09",
                        "isfull": 1,
                        "fullday": 30,
                        "eventhour": 0,
                        "create_time": 1725436589212,
                        "update_time": 1725436589212
                    }
                },
                {
                    "_id": {
                        "year": "2024",
                        "date": "2024-08"
                    },
                    "normoney": 5500,
                    "extmoney": 1200,
                    "allmark": "111;",
                    "works": {

                    }
                }
            ],
            "total": 11700
        }
    ]
}