MongoDB агрегирует по коллекциям строк заданного размера - PullRequest
0 голосов
/ 05 декабря 2018

возможно ли в MongoDB выполнять агрегацию по набору заранее заданного количества строк, а не группировать по.Например, я хочу вычислить среднее значение для каждых 1000 строк вместо группировки по определенному столбцу.Меньшим примером была бы таблица ниже, я хотел бы рассчитать Средний рейтинг каждых 4 последовательных строк:

enter image description here

Так что мой результат должен понравиться что-токак это:

enter image description here

Ниже приведены входные данные в формате JSON:

[{"ItemName":"Item1","Rating":4},
{"ItemName":"Item2","Rating":4},
{"ItemName":"Item2","Rating":4},
{"ItemName":"Item3","Rating":2},
{"ItemName":"Item4","Rating":5},
{"ItemName":"Item5","Rating":4},
{"ItemName":"Item6","Rating":2},
{"ItemName":"Item7","Rating":4},
{"ItemName":"Item8","Rating":1},
{"ItemName":"Item9","Rating":4},
{"ItemName":"Item10","Rating":3},
{"ItemName":"Item11","Rating":2},
{"ItemName":"Item12","Rating":2}]

1 Ответ

0 голосов
/ 06 декабря 2018

Легкого пути нет.Вам нужно будет сгруппировать всю коллекцию в массив, для чего может потребоваться allowDiskUse для больших наборов данных с огромным влиянием на производительность.

db.collection.aggregate([
    // count all documents
    { $group: {
        _id: null,
        cnt: { $sum: 1},
        docs: { $push: "$$ROOT" }
    } },
    // add _batch field to group documents by
    { $project: {
        _id: 0,
        docs: { $map: { 
            // add a sequential number to each
            input: { $zip: {
                inputs: [ "$docs",  { $range: [ 0, "$cnt" ] } ]
            } }, 
            as: "doc", 
            in: { $mergeObjects: [ 
                { $arrayElemAt: [ "$$doc", 0 ] }, 
                // split it in batches by 4 based on the sequential number
                { _batch: { $cond: [ 
                    { $eq: [ { $arrayElemAt: [  "$$doc", 1 ] }, 0 ] }, 
                    1, 
                    { $ceil: { $divide: [ { $arrayElemAt: [  "$$doc", 1 ] }, 4 ] } } 
                ] } }
            ] } 
        } }
    } },    
    { $unwind: "$docs" },
    { $replaceRoot: { newRoot: "$docs" } },
    // ensure original order, only if you need ItemRange as a string
    { $sort: { _id: 1 } },
    // calculate averages per batch
    { $group: { 
        _id: "$_batch",
        start: { $first: "$ItemName" }, // only if you need ItemRange as a string
        end: { $last: "$ItemName" }, // only if you need ItemRange as a string
        RatingAvg: {$avg: "$Rating"} 
    } },
    // only if you need them in order
    { $sort: { _id: 1 } },
    // calculate ItemRange, only if you need ItemRange as a string
    { $project: {
        _id: 0,
        ItemRange: { $concat: [ "$start", "-", "$end" ] },
        RatingAvg: 1 
    } },
])

Не уверен насчет практического варианта использования, так как все средние значения изменятся при удалениинапример, первый документ.

В любом случае, если вам не нужен ItemRange в формате «FirstName-LastName» и вы можете использовать вместо номера пакета, вы можете пропустить 2 последних сортировки в памяти, что должно повысить производительность.

...