How to fix mongo db query?

时间:2018-01-11 08:41:23

标签: node.js mongodb mongoose

I am writing a request for statistics from the db. Here's the code:

Stats.aggregate([
    {
        $group: {
            _id: {
                'advertiser': '$advertiser',
                'offer': '$offer'
            },
            stats: {
                $push: {
                    'date': '$date',
                    'spent': '$spent',
                    'revenue': '$revenue'
                }
            }
        }
    },
    {
        $group: {
            _id: '$_id.advertiser',
            offers: {
                $push: {
                    _id: '$_id.offer',
                    stats: '$stats'
                }
            }
        }
    }], callback);

I want that the advertiser had all his offers, and inside the offers there was statistics on the days along with spent and revenue. The problem is that statistics by day can be more than one and I get this answer:

stats   […]
0   {…}
date    2018-01-30T22:00:00.000Z
spent   100
revenue 200
1   {…}
date    2018-01-30T22:00:00.000Z
spent   20
revenue 20

But, I need to have the same days folded into one and spent and revenue added Also, I want to add offer info from offers collection into result offers, like I do with advertisers. Maybe someone know how to do this. Thank you

Stats in db:

{
"_id": {
    "$oid": "5a4f873d381727000404d171"
},
"advertiser": {
    "$oid": "5a4f74619f0251000438fe4a"
},
"offer": {
    "$oid": "5a4f748c9f0251000438fe4b"
},
"spent": 415.19,
"revenue": 780.92,
"date": "2018-01-02T22:00:00.000Z",
"user": {
    "$oid": "5a4f74259f0251000438fe40"
},
"__v": 0

}

Stats Schema

const StatsSchema = mongoose.Schema({
advertiser: {
    type: ObjectId,
    ref: 'Advertiser',
    required: true
},
offer: {
    type: ObjectId,
    ref: 'Offer',
    required: true
},
spent: {
    type: Number,
    required: true
},
revenue: {
    type: Number,
    required: true
},
date: {
    type: String,
    required: true
},
user: {
    type: ObjectId,
    ref: 'User',
    required: true
}});

1 个答案:

答案 0 :(得分:1)

您可以先对daymonthyear进行投影,然后进行相应的分组,如下所示。这是一个相对较长的查询,您可以根据您的工作流程在一些优化中添加。

db.createCollection('statistics');

db.statistics.insertMany([
    {advertiser: "1", offer: "1", date: "2018-01-30T22:00:00.000Z", spent: 10, revenue: 20},
    {advertiser: "1", offer: "1", date: "2018-01-30T21:00:00.000Z", spent: 20, revenue: 20},
    {advertiser: "2", offer: "2", date: "2018-01-30T22:00:00.000Z", spent: 10, revenue: 20},
    {advertiser: "2", offer: "2", date: "2018-01-30T21:00:00.000Z", spent: 1000, revenue: 2000},
    {advertiser: "2", offer: "2", date: "2018-01-31T22:00:00.000Z", spent: 25, revenue: 50}
])

transform_date = {
    $project: {
        advertiser: 1,
        offer: 1,
        date: { $dateFromString: { dateString: { $arrayElemAt: [ {$split: ["$date", "Z"]}, 0 ] }, timezone: 'UTC' } },
        spent: 1,
        revenue: 1      
    }
}

project_year_month_day = {
    $project: {
        advertiser: 1,
        offer: 1,
        date: 1,
        spent: 1,
        revenue: 1,
        year: { $year: "$date" },
        month: { $month: "$date" },
        day: { $dayOfMonth: "$date" }
    }
}

group_by_date_advertiser_offer_and_sum = {
    $group: {
        _id: {
            advertiser: "$advertiser",
            offer: "$offer",
            day: "$day",
            month: "$month",
            year: "$year"
        },
        spent: { $sum: "$spent" },
        revenue: { $sum: "$revenue" },
        dates: { $push: "$date" }
    }
}

group_advertiser_offer_and_push = {
    $group: {
        _id: {
            advertiser: "$_id.advertiser",
            offer: "$_id.offer"
        },
        stats: {
            $push: {
                dates: "$dates",
                spent: "$spent",
                revenue: "$revenue"
            }
        }
    }
}

group_advertiser_and_push = {
    $group: {
        _id: "$_id.advertiser",
        offers: {
            $push: {
                _id: "$_id.offer",
                stats: "$stats"
            }
        }
    }
}

db.statistics.aggregate([
    transform_date, 
    project_year_month_day, 
    group_by_date_advertiser_offer_and_sum, 
    group_advertiser_offer_and_push, 
    group_advertiser_and_push
])

<强>输出

[{
    "_id": "2",
    "offers": [{
        "_id": "2",
        "stats": [{
            "dates": [ISODate("2018-01-31T22:00:00Z")],
            "spent": 25,
            "revenue": 50
        }, {
            "dates": [ISODate("2018-01-30T22:00:00Z"), ISODate("2018-01-30T21:00:00Z")],
            "spent": 1010,
            "revenue": 2020
        }]
    }]
} {
    "_id": "1",
    "offers": [{
        "_id": "1",
        "stats": [{
            "dates": [ISODate("2018-01-30T22:00:00Z"), ISODate("2018-01-30T21:00:00Z")],
            "spent": 30,
            "revenue": 40
        }]
    }]
}]