带有条件group by语句的MongoDB查询

标签 mongodb mongodb-query aggregation-framework

我需要从mongoDB数据库导出客户记录。导出的客户记录不应具有重复的值。 “firstName+lastName+code”是对记录进行重复删除的关键,如果数据库中存在两条具有相同键的记录,那么我需要优先考虑具有电子邮件以外值的源字段。

客户 (id,firstName,lastName,code,source) 集合是这样的。

如果有 3 条记录具有相同的唯一键和 3 个不同的来源,那么我只需要在 2 个来源(电视、互联网)之间选择一条记录{或者如果有 n 个来源,我只需要一条记录}不与“电子邮件”(因为当只有一条记录具有唯一 key 并且来源是电子邮件时,将选择电子邮件) 查询使用:

db.customer.aggregate([
    {
        "$match": {
            "active": true,
            "dealerCode": { "$in": ["111391"] },
            "source": { "$in": ["email", "TV", "internet"] }
        }
    },
    {
        $group: {
            "_id": {
                "firstName": "$personalInfo.firstName",
                "lastName": "$personalInfo.lastName",
                "code": "$vehicle.code"
            },
            "source": {
                $addToSet: { "source": "$source" }
            }
        }
    },
    {
        $redact:
        {
            $cond: [
                { $eq: [{ $ifNull: ["$source", "other"] }, "email"] },
                "$$PRUNE",
                "$$DESCEND"
            ]
        }
    },
    {
        $project:
        {
            "source":
            {
                $map:
                {
                    "input": {
                        $cond: [
                            { $eq: [{ $size: "$source" }, 0] },
                            [{ "source": "email" }],
                            "$source"
                        ]
                    },
                    "as": "inp",
                    "in": "$$inp.source"
                }
            },
            "record": { "_id": 1 }
        }
    }
])

示例输出:

{ "_id" : { "firstName" : "sGI6YaJ36WRfI4xuJQzI7A==", "lastName" : "99eQ7i+uTOqO8X+IPW+NOA==", "code" : "1GTHK23688F113955" }, "source" : ["internet"] }
{ "_id" : { "firstName" : "WYDROTF/9vs9O7XhdIKd5Q==", "lastName" : "BM18Uq/ltcbdx0UJOXh7Sw==", "code" : "1G4GE5GV5AF180133" }, "source" : ["internet"] }
{ "_id" : { "firstName" : "id+U2gYNHQaNQRWXpe34MA==", "lastName" : "AIs1G33QnH9RB0nupJEvjw==", "code" : "1G4GE5EV0AF177966" }, "source" : ["internet"] }
{ "_id" : { "firstName" : "qhreJVuUA5l8lnBPVhMAdw==", "lastName" : "petb0Qx3YPfebSioY0wL9w==", "code" : "1G1AL55F277253143" }, "source" : ["TV"] }
{ "_id" : { "firstName" : "qhreJVuUA5l8lnBPVhMAdw==", "lastName" : "6LB/NmhbfqTagbOnHFGoog==", "code" : "1GCVKREC0EZ168134" }, "source" : ["TV", "internet"] }

此查询有问题,请提出建议:(

最佳答案

您的代码不起作用,因为 $cond不是累加器运算符。仅these累加器运算符,可以在 $group 阶段使用。

假设您的记录包含不超过两个可能的 source 值(正如您在问题中提到的那样),您可以添加条件 $project 阶段并将 $group 阶段修改为,

代码:

    db.customer.aggregate([
        {
            $group: {
                "_id": {
                    "id": "$id",
                    "firstName": "$firstName",
                    "lastName": "$lastName",
                    "code": "$code"
                },
                "sourceA": { $first: "$source" },
                "sourceB": { $last: "$source" }
            }
        },
        {
            $project: {
                "source": {
                    $cond: [
                        { $eq: ["$sourceA", "email"] },
                        "$sourceB",
                        "$sourceA"
                    ]
                }
            }
        }
    ])

如果源的可能值超过两个,那么您可以执行以下操作:

  • idfirstNamelastNamecode 分组。积累 source 的唯一值,使用 $addToSet运算符。
  • 使用$redact仅保留 email 以外的值。
  • Project必填字段,如果source数组为空(所有元素已被删除),则添加一个 值 email 给它。
  • 展开源字段将其列为字段而不是数组。 (可选)

代码:

    db.customer.aggregate([
        {
            $group: {
                "_id": {
                    "id": "$id",
                    "firstName": "$firstName",
                    "lastName": "$lastName",
                    "code": "$code"
                },
                "sourceArr": { $addToSet: { "source": "$source" } }
            }
        },
        {
            $redact: {
                $cond: [
                    { $eq: [{ $ifNull: ["$source", "other"] }, "email"] },
                    "$$PRUNE",
                    "$$DESCEND"
                ]
            }
        },
        {
            $project: {
                "source": {
                    $map: {
                        "input":
                        {
                            $cond: [
                                { $eq: [{ $size: "$sourceArr" }, 0] },
                                [{ "source": "item" }],
                                "$sourceArr"]
                        },
                        "as": "inp",
                        "in": "$$inp.source"
                    }
                }
            }
        }
    ])

关于带有条件group by语句的MongoDB查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28229496/

相关文章:

MongoDB 使用 or 查询超集中的子集

mongodb - 查询以将文档的交集与字段集体匹配

mongodb - MongoDB 中 $project、$filter 和 $match 之间的区别

ruby - gems/anemone-0.7.2/lib/anemone/storage.rb:28:in `MongoDB' : 未初始化的常量 Mongo::Connection (NameError)

php - 在浏览器上显示保存在 gridfs 中的 pdf 文件的预览

java - mongo中根据出现次数排序

mongodb - 将对象数组中的数组字段连接到 mongodb 聚合中的一个字符串字段中

mongodb - 使用数组源获取 mongodb 中的数组子集

javascript - mongoDB保存数据失败

c# - 使用 C# MongoDB 查询嵌套文档