【问题标题】:Filter output from multiple collections过滤来自多个集合的输出
【发布时间】:2019-08-24 02:41:02
【问题描述】:

假设我们有一个这样的脚本数组:

 ["xxxxx1","xxxxx2","xxxxx3","xxxxx4"] 

我们在 db 中存在以下脚本集合:

Executed:{"_id" : ObjectId("xxx"),"scrip" : "xxxxx1" },{"_id" : ObjectId("xxy"),"scrip" : "xxxxx3" }......
In-process:{"_id" : ObjectId("xxx"),"scrip" : "xxxxx4" }, ....
Rejected:{"_id" : ObjectId("xxx"),"scrip" : "xxxxx5" }....

我们希望得到上述任何集合中都不存在的脚本数组。 预期输出:

["xxxxx2"]

这如何在单个 mongodb 管道/查询中完成?

【问题讨论】:

  • 你能详细说明一下脚本的集合吗,它是来自查询还是这些对象数组保存在数据库中
  • 它们被保存为针对请求保存的对象数组 - { "requestid" : 'R1', "stocks" : ["xxxxx1","xxxxx2","xxxxx3","xxxxx4" ] }
  • “数据库中存在的脚本集合”如何从查询中保存/获取?它们是保存在特定数据库中的数组(已执行、已拒绝、正在处理)吗
  • 您可以 $filter 已执行、已拒绝、正在处理的数组,然后连接它们,然后 $setDifference betweenstocks 数组和连接数组
  • (Executed, Rejected, In-process) 是与查询请求在同一数据库中的脚本文档的单独集合 - 结构如上所示

标签: mongodb mongodb-query aggregation-framework mongodb-java


【解决方案1】:

以下查询可以得到我们预期的输出:

db.executed.aggregate([
    {
        $group:{
            "_id":null,
            "executedScrips":{
                $addToSet:"$scrip"
            }
        }
    },
    {
        $lookup:{
            "from":"inprocess",
            "pipeline":[
                {
                    $group:{
                        "_id":null,
                        "inprocessScrips":{
                            $addToSet:"$scrip"
                        }
                    }
                }
            ],
            "as":"inprocessLookup"
        }
    },
    {
        $lookup:{
            "from":"rejected",
            "pipeline":[
                {
                    $group:{
                        "_id":null,
                        "rejectedScrips":{
                            $addToSet:"$scrip"
                        }
                    }
                }
            ],
            "as":"rejectedLookup"
        }
    },
    {
        $unwind:{
            "path":"$inprocessLookup",
            "preserveNullAndEmptyArrays":true
        }
    },
    {
        $unwind:{
            "path":"$rejectedLookup",
            "preserveNullAndEmptyArrays":true
        }
    },
    {
        $project:{  
            "scrips":{
                $concatArrays:[
                    "$executedScrips", 
                    {
                        $ifNull:["$inprocessLookup.inprocessScrips",[]]
                    },
                    {
                        $ifNull:["$rejectedLookup.rejectedScrips",[]]
                    }
                ]
            }
        }
    },
    {
        $project:{
            "_id":0,
            "notFound":{
                $setDifference:[["xxxxx1","xxxxx2","xxxxx3","xxxxx4"],"$scrips"]
            }
        }
    }
]).pretty()

数据集:

收藏:executed

    { "_id" : ObjectId("5d60e572f00e0c8c3593b5ff"), "scrip" : "xxxxx1" }
    { "_id" : ObjectId("5d60e572f00e0c8c3593b600"), "scrip" : "xxxxx3" }

收藏:inprocess

    { "_id" : ObjectId("5d60f23ff00e0c8c3593b601"), "scrip" : "xxxxx4" }

收藏:rejected

    { "_id" : ObjectId("5d60f260f00e0c8c3593b602"), "scrip" : "xxxxx5" }

输出:

{ "notFound" : [ "xxxxx2" ] }

注意:如果executed 集合中没有记录,则查询将失败,因为聚合从那里开始。


更新一:将传递请求数组而不是脚本数组

以下查询可以得到我们预期的输出:

db.executed.aggregate([
    {
        $group:{
            "_id":null,
            "executedScrips":{
                $addToSet:"$scrip"
            }
        }
    },
    {
        $lookup:{
            "from":"inprocess",
            "pipeline":[
                {
                    $group:{
                        "_id":null,
                        "inprocessScrips":{
                            $addToSet:"$scrip"
                        }
                    }
                }
            ],
            "as":"inprocessLookup"
        }
    },
    {
        $lookup:{
            "from":"rejected",
            "pipeline":[
                {
                    $group:{
                        "_id":null,
                        "rejectedScrips":{
                            $addToSet:"$scrip"
                        }
                    }
                }
            ],
            "as":"rejectedLookup"
        }
    },
    {
        $unwind:{
            "path":"$inprocessLookup",
            "preserveNullAndEmptyArrays":true
        }
    },
    {
        $unwind:{
            "path":"$rejectedLookup",
            "preserveNullAndEmptyArrays":true
        }
    },
    {
        $project:{  
            "scrips":{
                $concatArrays:[
                    "$executedScrips", 
                    {
                        $ifNull:["$inprocessLookup.inprocessScrips",[]]
                    },
                    {
                        $ifNull:["$rejectedLookup.rejectedScrips",[]]
                    }
                ]
            }
        }
    },
    {
        $addFields:{
            "requests":[
                {
                    "requestid" : "R1", 
                    "stocks" : ["xxxxx1","xxxxx2","xxxxx3","xxxxx4"]
                },
                {
                    "requestid" : "R2", 
                    "stocks" : ["xxxxx1","xxxxx3","xxxxx4"]
                },
                {
                    "requestid" : "R3", 
                    "stocks" : ["xxxxx1","xxxxx3","xxxxx4","xxxxx10"]
                }
            ]
        }
    },
    {
        $project:{
            "_id":0,
            "unmatchedRequests":{
               $map:{
                    "input":"$requests",
                    "as":"request",
                    "in":{
                        $concat:{
                            $cond:[
                                {
                                    $gt:[
                                        {
                                            $size:{
                                                $setDifference:["$$request.stocks","$scrips"]
                                            }
                                        },
                                        0
                                    ]
                                },
                                "$$request.requestid",
                                null
                            ]
                        }
                    }
               }
            }
        }
    },
    {
        $project:{
            "unmatchedRequests":{
                $filter:{
                    "input":"$unmatchedRequests",
                    "as":"unmatchedRequest",
                    "cond":{
                        $ne:["$$unmatchedRequest",null]
                    }
                }
            }
        }
    }
]).pretty()

输出:

{ "unmatchedRequests" : [ "R1", "R3" ] }

注意:在第 7 个聚合阶段,我们正在注入请求数组。

【讨论】:

  • 会试试这个!!感谢这个。如果我们要获得至少一个不匹配的脚本的请求数组 - 每个请求都是 { "requestid" : 'R1', "stocks" : [" xxxxx1","xxxxx2","xxxxx3","xxxxx4"] } ;如何调整
  • @IUnknown 对不起,但没有完全了解您。对于每个请求,您都需要此 unmatched scrip(s) 信息吗?
  • 至少有一个脚本不匹配的请求数组(而不是请求的组成脚本数组)。因此预期的输出将是 ['R1']
  • @IUnknown 为新需求添加了 mongo 查询。
  • 如果我需要拉入请求集合而不是注入硬编码文档,addfield 如何工作
猜你喜欢
  • 2018-02-20
  • 2017-11-11
  • 2020-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多