从展开的数组中获取最大值

时间:2018-10-26 04:09:09

标签: mongodb aggregation-framework

我有一个文档集合,我想在这些文档中找到data对象中每个可能的字段对的每个比率的最大值。例如:

文档:

[
    { data: { a: 1, b: 5, c: 2 } },
    { data: { a: 4, b: 1, c: 1 } },
    { data: { a: 2, b: 4, c: 3 } }
]

所需的输出:

{
    a: { a: 1, b: 4, c: 4   },
    b: { a: 5, b: 1, c: 2.5 },
    c: { a: 2, b: 1, c: 1   }
}

因此,输出a.b是a:b比率1/54/12/4中最大的比率。

所以我想我首先使用$objectToArray来转换data,然后对结果进行$unwind转换,但是我很难弄清楚如何将所有内容组合在一起。我所拥有的文档数量不会太大,但是data中的键数量可以低至数千,因此我不确定Mongo能够处理多堆{ {1}},并比较类似的值。

1 个答案:

答案 0 :(得分:1)

您可以尝试以下聚合:

db.col.aggregate([
    {
        $addFields: { data: { $objectToArray: "$data" } }
    },
    {
        $project: {
            pairs: {
                $map: {
                    input: { $range: [ 0, { $multiply: [ { $size: "$data" }, { $size: "$data" } ] } ] },
                    as: "index",
                    in: {
                        $let: {
                            vars: {
                                leftIndex: { $floor: { $divide: [ "$$index", { $size: "$data" } ] } },
                                rightIndex: { $mod: [ "$$index", { $size: "$data" } ] }
                            },
                            in: {
                                l: { $arrayElemAt: [ "$data", "$$leftIndex" ] },
                                r: { $arrayElemAt: [ "$data", "$$rightIndex" ] }
                            }
                        }
                    }
                }
            }
        }
    },
    { $unwind: "$pairs" },
    {
        $group: {
            _id: { l: "$pairs.l.k", r: "$pairs.r.k" },
            value: { $max: { $divide: [ "$pairs.l.v", "$pairs.r.v" ]  } }
        }
    },
    {
        $sort: {
            "_id.l": 1, "_id.r": 1
        }
    },
    {
        $group: {
            _id: "$_id.l",
            values: { $push: { k: "$_id.r", v: "$value"  } }
        }
    },
    {
        $addFields: { values: { $arrayToObject: "$values" } }
    },
    {
        $project: {
            root: [ { k: "$_id", v: "$values" } ]
        }
    },
    {
        $sort: { "root.k": 1 }
    },
    {
        $replaceRoot: {
            newRoot: {
                $arrayToObject: "$root"
            }
        }
    }
])

基本上,您需要$objectToArray$arrayToObject在数组和对象之间进行转换。基本上,关键是要为每个对象生成nxn对(在这种情况下为3x3=9)。您可以使用$range运算符执行此类迭代。然后将$mod$divide$floor一起使用,您可以获得类似(0,0)...(2,2)的索引对。然后,您只需要$group$max来获取每种货币对类型的最大值(例如ab等)。要获得最终形状,您还需要$replaceRoot

输出:

{ "a" : { "a" : 1, "b" : 4, "c" : 4 } }
{ "b" : { "a" : 5, "b" : 1, "c" : 2.5 } }
{ "c" : { "a" : 2, "b" : 1, "c" : 1 } }