MongoDB Суммарный рост сумм - PullRequest
       25

MongoDB Суммарный рост сумм

0 голосов
/ 11 января 2019

У меня есть канал агрегации MondoDB, который выводит ежедневную сумму дохода путем агрегирования всех Sales:

Sale.aggregate
    ([
        {
            $project: {
                day: { $substr: ['$createdAt', 0, 10], },
            },
        },
        {
            $group: {
                _id: '$day',
                earnings: { $sum: '$pricing.earnings' },
            },
        },
        {
            $sort: {
                _id: 1
            }
        },
        {
            $project: {
                date: '$_id',
                earnings: '$earnings',
            },
        },
        {
            $group: {
                _id: null,
                stats: { $push: '$$ROOT' },
            }
        },
        {
            $project: {
                stats: {
                    $map: {
                        // returns an array with all dates between 2 provided params
                        input: dates.daysArray(dates.getDay(user.createdAt), dates.today()),
                        as: 'date',
                        in: {
                            $let: {
                                vars: { index: { $indexOfArray: ['$stats._id', '$$date'] } },
                                in: {
                                    $cond: {
                                        if: { $ne: ['$$index', -1] },
                                        then: { $arrayElemAt: ['$stats', '$$index'] },
                                        else: { _id: '$$date', date: '$$date', earnings: 0 }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        {
            $unwind: '$stats'
        },
        {
            $replaceRoot: {
                newRoot: '$stats'
            }
        },
        {
            $project: {
                _id: 0,
                x: '$date',
                y: '$earnings',
            },
        },
    ])

Вывод этой трубы может выглядеть следующим образом:

[
    {
        x: '2019-01-09',
        y: 10,
    },
    {
        x: '2019-01-10',
        y: 5,
    },
    {
        x: '2019-01-11',
        y: 20,
    }
]

Это означает, что на 2019-01-09 были продажи на сумму $ 10, на 2019-01-10 $ 5 и т. Д.

Теперь я не хочу ежедневный заработок, но сумму всех заработанных доходов. Это означает, что результат должен выглядеть следующим образом:

[
    {
        x: '2019-01-09',
        y: 10, // a total of $10 on the first day
    },
    {
        x: '2019-01-10',
        y: 15, // a total of $15 on the second day (10 + 5)
    },
    {
        x: '2019-01-11',
        y: 35, // a total of $35 on the third day (15 + 20)
    }
]

Так что в основном я не хочу ежедневную сумму, а рост.

P.S .: Я использую эти данные для отображения на графике.

Ответы [ 2 ]

0 голосов
/ 12 января 2019

Вы можете добавить следующие этапы в дополнение к тому, что у вас есть

логика: $push x и y для массива, итерируйте массив, используя $range по индексу, для x получите $arrayElemAt при index, для y $slice и $sum до index+1

db.t51.aggregate([
    {$group : {_id : null, x : {$push : "$x"}, y : {$push : "$y"}}},
    {$project : {data : {
        $map : { 
            input : {$range : [0, {$size : "$x"}]},
            as : "idx",
            in : { x : {$arrayElemAt : ["$x", "$$idx"]}, y : {$sum : {$slice : ["$y", {$sum : ["$$idx",1]}]}}}}
    }}},
    {$unwind : "$data"},
    {$replaceRoot: {newRoot : "$data"}}
]).pretty()

если у вас есть больше полей для агрегирования или прогнозирования, вы можете использовать ниже этапов

db.t51.aggregate([
    {$group : {_id : null, data : {$push : "$$ROOT"}}}, 
    {$addFields : {data : 
        {$reduce : {
            input : "$data", 
            initialValue : [{y : 0}], 
            in : {$concatArrays : [ "$$value",[{$mergeObjects : ["$$this", { y : {$sum : ["$$this.y",{$arrayElemAt : ["$$value.y", -1]}]}}]}]]}
        }}
    }},
    {$addFields : {data : {$slice : ["$data", 1, {$size : "$data"}]}}},
    {$unwind : "$data"},
    {$replaceRoot: {newRoot : "$data"}}
]).pretty()
0 голосов
/ 11 января 2019

Aggregation Framework обрабатывает все документы независимо (по замыслу), поэтому они не знают друг о друге. Единственный способ изменить это - использовать $ group . Установка _id в null позволяет вам захватывать данные из всех документов в один. Затем вы можете перебирать эти массивы (используя $ range для получения массива индексов и $ map для возврата другого массива). Легко получить x ( $ arrayElemAt ), а для y вам нужно сложить все элементы массива, используя $ reduce . Ввод для $reduce генерируется оператором $ slice и зависит от индекса (для 0 это будет [10], для 1 [10,5] и т. Д.). Чтобы завершить запрос, вам нужно $ unwind и $ replaceRoot , чтобы получить оригинальную форму документа.

db.col.aggregate([
    {
        $sort: { x: 1 }
    },
    {
        $group: {
            _id: null,
            xArr: { $push: "$x" },
            yArr: { $push: "$y" }
        }
    },
    {
        $project: {
            data: {
                $map: {
                    input: { $range: [ 0, { $size: "$xArr" } ] },
                    as: "i",
                    in: {
                        x: { $arrayElemAt: [ "$xArr", "$$i" ] },
                        y: {
                            $reduce: {
                                input: { $slice: [ "$yArr", { $add: [ "$$i", 1 ] } ] },
                                initialValue: 0,
                                in: { $add: [ "$$this", "$$value" ] }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        $unwind: "$data"
    },
    {
        $replaceRoot: {
            newRoot: "$data"
        }
    }
])

Полагаю, вам нужно добавить вышеперечисленные шаги к вашей существующей агрегации. Чтобы доказать, что это работает, вы можете запустить его для отдельной коллекции:

db.col.save({ x: '2019-01-09', y: 10 })
db.col.save({ x: '2019-01-10', y: 5 })
db.col.save({ x: '2019-01-11', y: 20 })

и выводит:

{ "x" : "2019-01-09", "y" : 10 }
{ "x" : "2019-01-10", "y" : 15 }
{ "x" : "2019-01-11", "y" : 35 }
...