Получите максимум от размотанных массивов

У меня есть набор документов, в которых я хочу найти максимальные значения каждого отношения каждой возможной пары полей в объекте 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/5, 4/1 и 2/4.

Итак, я полагаю, что сначала использую $objectToArray для преобразования data, а затем $unwind для результата, но мне трудно понять, как сгруппировать все вместе. Количество документов, которые у меня есть, не будет слишком большим, но количество ключей в data может составлять несколько тысяч, поэтому я не уверен, насколько хорошо Mongo сможет обрабатывать кучу $lookup и сравнивать значения. как это.

2
0
43
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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). Вы можете выполнить такую ​​итерацию с помощью оператора $ диапазон. Затем, используя $ мод и $ разделить с $ этаж, вы можете получить пары индексов, такие как (0,0)...(2,2). Тогда вам просто понадобится $ группа с $ макс, чтобы получить максимальные значения для каждого типа пары (например, a с b и так далее). Для окончательной формы вам также понадобится $ replaceRoot.

Выходы:

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

Другие вопросы по теме