【问题标题】:compare two array elements with conditions in mongodb aggregation将两个数组元素与mongodb聚合中的条件进行比较
【发布时间】:2021-04-10 19:59:11
【问题描述】:

我有文件

[{
        "id": "1",
        "base": 23,
        "dateValues": [{
            "timestamp": "2021-02-15T13:13:17.611Z",
            "value": 50
        }, {
            "timestamp": "2021-02-22T13:13:17.611Z",
            "value": 50
        }]
    },
    {
        "id": "2",
        "base": 256,
        "dateValues": [{
            "timestamp": "2021-02-01T13:13:17.611Z",
            "value": 50
        }, {
            "timestamp": "2021-02-10T13:13:17.611Z",
            "value": 50
        }]
    },
    {
        "id": "3",
        "base": 256,
        "dateValues": [{
            "timestamp": "2021-02-03T13:13:17.611Z",
            "value": 50
        }, {
            "timestamp": "2021-02-04T13:13:17.611Z",
            "value": 50
        }, {
            "timestamp": "2021-02-10T13:13:17.611Z",
            "value": 50
        }]
    },
    {
        "id": "4",
        "base": 256,
        "dateValues": [{
            "timestamp": "2021-02-03T13:13:17.611Z",
            "value": 50
        }, {
            "timestamp": "2021-02-08T13:13:17.611Z",
            "value": 50
        }]
    }
]

现在我想比较所有对象的日期。我将尽可能简单地简化逻辑..

  1. 首先我想获取所有不同的日期集,因此这些日期将是
"2021-02-01"
"2021-02-03"
"2021-02-04"
"2021-02-08"
"2021-02-15"
"2021-02-22"
"2021-02-10"
  1. 现在我想循环上面的日期并将每个日期与每个对象 dateValues 进行比较

例如,如果我们取第一个日期“2021-02-01”,我希望每个对象(文档)只有一个日期

  • 小于等于“2021-02-01”的人
  • 其时间戳是最新的时间戳
  • 如果没有找到 dateValue,那么我们就取基值
  • 最后我们将对这些值求和

所以对于这个日期“2021-02-01” dateValues 将是

for id 1 no date value is there so in this case I need to take base value, which is 23
for id 2 we found date value so we will take its corresponding value, which is 50
for id 3 and 4 no date is matching so again we are taking its base value which 256 and 256
so final value comes for date "2021-02-01" is 23+50+256+256 = 585

日期 “2021-02-22”

的另一个示例
for id 1 we found date "2021-02-22", value is 50
for id 2 we found date "2021-02-10" value is 50
for id 3 we found date "2021-02-10" value is 50
for id 4 we found date "2021-02-08" value is 50
Final value for date "2021-02-22" is 200

我们可以在 mongo db 聚合中执行此逻辑吗? 我只能得到不同的日期,但在那之后我失去了它。谁能帮我解决这个 mongodb 聚合?或者甚至可以在 mongodb 聚合中实现这个逻辑?

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    Mongo 聚合框架有 很多 强大的运算符,它基本上归结为以正确的顺序链接阶段和运算符。

    假设您有一个名为 st 的集合中的文档。

    解释:

    • Unwind 和 Group 将在每个日期为您提供一份文件
    • 在同一集合中查找每个日期的所有文档
    • 在查找期间将查找中的管道应用于所有文档以查找与日期匹配的 dateValue 或返回基数。
    • 汇总记录
    [
        { $unwind: "$dateValues" },
        { $group: {
            _id: "$dateValues.timestamp"
        }},
        { $lookup: {
            from: "st",
            as: "records",
            let: { date: "$_id" },
            pipeline: [
                { $project: {
                    base: 1,
                    dateValues: {
                        $filter: {
                            input: "$dateValues",
                            as: "dateValue",
                            cond: {
                                $eq: ["$$dateValue.timestamp", "$$date"]
                            }
                        }
                    }
                }},
                { $project: {
                    val: { $cond: {
                        if: {$eq: [ {$size: "$dateValues"}, 1]},
                        then: "$dateValues.0.value",
                        else: "$base"
                    }}
                }},
            ],
        }},
        { $project: {
            _id: 1,
            finalValue: {
                $sum: "$records.val"
            }
        }}
    ]
    

    结果:

    { "_id" : "2021-02-22T13:13:17.611Z", "finalValue" : 768 }
    { "_id" : "2021-02-01T13:13:17.611Z", "finalValue" : 535 }
    { "_id" : "2021-02-15T13:13:17.611Z", "finalValue" : 768 }
    { "_id" : "2021-02-04T13:13:17.611Z", "finalValue" : 535 }
    { "_id" : "2021-02-10T13:13:17.611Z", "finalValue" : 279 }
    { "_id" : "2021-02-03T13:13:17.611Z", "finalValue" : 279 }
    { "_id" : "2021-02-08T13:13:17.611Z", "finalValue" : 535 }
    

    注意:请仔细检查$filter$cond 并确保它符合您的要求。

    更新的管道: 添加了一个reduce阶段

    • 过滤阶段选择时间戳dateValues。
    • reduce 阶段选择其中最大的dateValue
    [
            { $unwind: "$dateValues" },
            { $group: {
                _id: "$dateValues.timestamp"
            }},
            { $lookup: {
                from: "st",
                as: "records",
                let: { date: "$_id" },
                pipeline: [
                    { $project: {
                        base: 1,
                        dateValues: {
                            $filter: {
                                input: "$dateValues",
                                as: "dateValue",
                                cond: { $lte: ["$$dateValue.timestamp", "$$date"] },
                            }
                        }
                    }},
                    { $project: {
                        base: 1,
                        dateValues: {
                            $reduce: {
                                input: "$dateValues",
                                initialValue: null,
                                    in: { $cond: {
                                        if: { $gt: ["$$this.timestamp", "$$value.timestamp"] },
                                        then: "$$this",
                                        else: "$$value"
                                    }}
                            }
                        }
                    }},
                    { $project: {
                        val: { $cond: {
                            if: {$eq: ["$dateValues", null]},
                            then: "$base",
                            else: "$dateValues.value",
                        }}
                    }},
                ],
            }},
            { $project: {
                _id: 1,
                finalValue: {
                    $sum: "$records.val"
                }
            }}
    ]
    

    【讨论】:

    • 感谢@Ramit 的帮助。真的很感激 :) 我试过了,但它不是最新的日期。我的意思是,如果我们采用日期“2021-02-22”进行比较,它应该采用小于等于的日期并且它应该具有最新的时间戳。目前我们只取第一个数组元素。我尝试对数组进行排序并将其分组,但总和没有正确发生..
    • 对不起,比较后日期是一样的,而且“val”被最后一个对象覆盖,所以“val”的计算对所有人都是一样的。
    猜你喜欢
    • 1970-01-01
    • 2019-09-16
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多