Mongo查询数组是一个子数组

时间:2019-09-02 20:14:23

标签: mongodb aggregation-framework

我正在寻找一个充当$setIsSubset的查询,但不考虑重复值。

例如,[1,1,2,3][1,2,3,4]的子集,因为集合没有重复的值。

如何编写查询,使[1,1,2,3]不是[1,2,3,4]的子集?

预期输出示例:

INPUT     |  TARGET  | RESULT
[1]        [1,2,3,4]   TRUE
[1,2,3]    [1,2,3,4]   TRUE
[1,1,2,3]  [1,2,3,4]   FALSE
[1,2,3,4]  [1,2,3,4]   TRUE
[1,3]      [1,2,3,4]   TRUE
[1,11,5]   [1,2,3,4]   FALSE
[1,2,2,3]  [1,2,3,4]   FALSE

2 个答案:

答案 0 :(得分:2)

我建议不要在mongo查询中进行如此繁琐的处理,因为您可以使用任何编程语言轻松地完成相同的任务。但是,如果您仍需要mongo,则只要对输入数组和目标数组都进行了排序,以下查询可以为您提供预期的输出。

db.collection.aggregate([
    {
        $project:{
            "modifiedInput":{
                $reduce:{
                    "input":"$input",
                    "initialValue":{
                        "data":[],
                        "postfix":0,
                        "index":0,
                        "nextElem":{
                            $arrayElemAt:["$input",1]
                        }
                    },
                    "in":{
                        "data":{
                            $concatArrays:[
                                "$$value.data",
                                [
                                    {
                                        $concat:[
                                            {
                                                $toString:"$$this"
                                            },
                                            "-",
                                            {
                                                $toString:"$$value.postfix"
                                            }
                                        ]
                                    }
                                ]
                            ]
                        },
                        "postfix":{
                            $cond:[
                                {
                                    $eq:["$$this","$$value.nextElem"]
                                },
                                {
                                    $sum:["$$value.postfix",1]
                                },
                                0
                            ]
                        },
                        "nextElem": {
                            $arrayElemAt:["$input", { $sum : [ "$$value.index", 2] }]
                        },
                        "index":{
                            $sum:["$$value.index",1]
                        }
                    }
                }
            },
            "modifiedTarget":{
                $reduce:{
                    "input":"$target",
                    "initialValue":{
                        "data":[],
                        "postfix":0,
                        "index":0,
                        "nextElem":{
                            $arrayElemAt:["$target",1]
                        }
                    },
                    "in":{
                        "data":{
                            $concatArrays:[
                                "$$value.data",
                                [
                                    {
                                        $concat:[
                                            {
                                                $toString:"$$this"
                                            },
                                            "-",
                                            {
                                                $toString:"$$value.postfix"
                                            }
                                        ]
                                    }
                                ]
                            ]
                        },
                        "postfix":{
                            $cond:[
                                {
                                    $eq:["$$this","$$value.nextElem"]
                                },
                                {
                                    $sum:["$$value.postfix",1]
                                },
                                0
                            ]
                        },
                        "nextElem": {
                            $arrayElemAt:["$target", { $sum : [ "$$value.index", 2] }]
                        },
                        "index":{
                            $sum:["$$value.index",1]
                        }
                    }
                }
            }
        }
    },
    {
        $project:{
            "_id":0,
            "matched":{
                $eq:[
                    {
                        $size:{
                            $setDifference:["$modifiedInput.data","$modifiedTarget.data"]
                        }
                    },
                    0
                ]
            }
        }
    }
]).pretty()

数据集:

{
    "_id" : ObjectId("5d6e005db674d5c90f46d355"),
    "input" : [
        1
    ],
    "target" : [
        1,
        2,
        3,
        4
    ]
}
{
    "_id" : ObjectId("5d6e005db674d5c90f46d356"),
    "input" : [
        1,
        2,
        3
    ],
    "target" : [
        1,
        2,
        3,
        4
    ]
}
{
    "_id" : ObjectId("5d6e005db674d5c90f46d357"),
    "input" : [
        1,
        1,
        2,
        3
    ],
    "target" : [
        1,
        2,
        3,
        4
    ]
}
{
    "_id" : ObjectId("5d6e005db674d5c90f46d358"),
    "input" : [
        1,
        2,
        3,
        4
    ],
    "target" : [
        1,
        2,
        3,
        4
    ]
}
{
    "_id" : ObjectId("5d6e005db674d5c90f46d359"),
    "input" : [
        1,
        3
    ],
    "target" : [
        1,
        2,
        3,
        4
    ]
}
{
    "_id" : ObjectId("5d6e005db674d5c90f46d35a"),
    "input" : [
        1,
        5,
        11
    ],
    "target" : [
        1,
        2,
        3,
        4
    ]
}
{
    "_id" : ObjectId("5d6e005db674d5c90f46d35b"),
    "input" : [
        1,
        2,
        2,
        3
    ],
    "target" : [
        1,
        2,
        3,
        4
    ]
}

输出:

{ "matched" : true }
{ "matched" : true }
{ "matched" : false }
{ "matched" : true }
{ "matched" : true }
{ "matched" : false }
{ "matched" : false }

说明::为避免消除相同的值,我们为每个值添加了后缀计数器。例如,[1,1,1,2,3,3,4,4]将变为[“ 1-0”,“ 1-1”,“ 1-2”,“ 2-0”,“ 3- 0“,” 3-1“,” 4-0“,” 4-1“,” 4-2“]]。输入和目标数组转换后,将计算出设置的差。如果设置差异的大小为零,那就是匹配。

答案 1 :(得分:1)

您可以尝试以下汇总:

let input = [1,2,3];
let inputSize = 3;

db.collection.aggregate([
    {
        $project: {
            uniqueTarget: { $setUnion: [ "$target" ] }
        }
    },
    {
        $addFields: {
            filtered: {
                $reduce: {
                    input: input,
                    initialValue: "$uniqueTarget",
                    in: { 
                        $filter: { 
                            input: "$$value", 
                            as: "current", 
                            cond: { $ne: [ "$$this", "$$current" ] } 
                        } 
                    } 
                }
            }
        }
    },
    {
        $project: {
            result: { 
                $eq: [ 
                    { $size: "$filtered" }, 
                    { $subtract: [ { $size: "$uniqueTarget" }, inputSize ] } 
                ] 
            }
        }
    }
])

它以$setUnion开头,以确保target数组中没有重复项。然后,您可以运行$reduce遍历input并从目标中删除当前处理的元素。每次迭代都应删除单个元素,以使filtered的{​​{3}}等于uniqueTarget-inputSize的{​​{3}}

$size

$size