如何从聚合输出中展平JSON结果

时间:2018-03-24 10:47:28

标签: javascript node.js mongodb mongoose aggregation-framework

使用mongo db聚合我编写了以下NodeJs api。我得到了输出但没有得到我预期的输出,所以如何做到这一点可以帮助我解决这个问题吗?

app.get('/polute', function (req, res) {
    Light.aggregate([ 
        { $match: {
            CREATE_DATE: {
                $lte:new Date(),
                $gte: new Date(new Date().setDate(new 
                    Date().getDate()-120)
                )
            }
        } },
        { $group: {
            _id:{ 
                month: { $month: "$CREATE_DATE" },
                year: { $year: "$CREATE_DATE" }
            },
            avgofozone:{$avg:"$OZONE"}
        } },
        { $sort:{ "year": -1 } },
        { $project: {
            year: '$_id.year',
            avgofozone: '$avgofozone',
            month: '$_id.month',_id:0
        } }
   ], function (err, polute) {
       console.log("naresh:" +JSON.stringify(polute));
        res.json(polute);
   });
});

实际输出:

[
    { "avgofozone" : 21.07777777777778, "year" : 2018, "month" : 2 }
    { "avgofozone" : 17.8, "year" : 2018, "month" : 3 }
    { "avgofozone" : 17.8, "year" : 2018, "month" : 1 }
]

预期输出:

[
    { 
        "zone_type": "avgofozone", 
        "year": 2018, 
        "February": 21.07777777777778, 
        "March": 17.8, 
        "January": 17.8 
    }
] 

1 个答案:

答案 0 :(得分:1)

使用MongoDb 3.6及更高版本,您可以利用 $arrayToObject 运算符和 $replaceRoot 管道来获取所需的JSON输出。您需要运行以下聚合管道:

const monthsEnum = {
    "_id": "year",
    "1": "January",
    "2": "February",
    "3": "March",
    "4": "April",
    "5": "May",
    "6": "June",
    "7": "July",
    "8": "August",
    "9": "September",
    "10": "October",
    "11": "November",
    "12": "December"
};

Light.aggregate([ 
    { "$match": {
        "CREATE_DATE": {
            "$lte": new Date(),
            "$gte": new Date(new Date().setDate(new Date().getDate()-120))
        }
    } },
    { "$group": {
        "_id": { 
            "month": { "$month": "$CREATE_DATE" },
            "year": { "$year": "$CREATE_DATE" }
        },
        "avgofozone": { "$avg": "$OZONE" }
    } },
    { "$group": {
        "_id": "$year",
        "avgs": {
            "$push": {
                "k": { "$substr": ["$month", 0, -1 ] },
                "v": "$avgofozone"
            }
        }
    } },
    { "$replaceRoot": { 
        "newRoot": { 
            "$mergeObjects": [ 
                { "$arrayToObject": "$avgs" }, 
                "$$ROOT" 
             ] 
        } 
    } },
    { "$project": { "avgs": 0 } }
], (err, data) => {
    console.log("naresh:" +JSON.stringify(data));
    const polute = Object.keys(data).reduce((p, c) => ({...p, monthsEnum[c]: data[c]}), {});
    res.json(polute);
})

仅使用聚合管道进行整形,您可以使用 $let 运算符将月份索引映射到数组中的值。考虑运行以下管道:

const MONTHS = [, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

Light.aggregate([ 
    { "$match": {
        "CREATE_DATE": {
            "$lte": new Date(),
            "$gte": new Date(new Date().setDate(new Date().getDate()-120))
        }
    } },
    { "$group": {
        "_id": { 
            "month": { "$month": "$CREATE_DATE" },
            "year": { "$year": "$CREATE_DATE" }
        },
        "avgofozone": { "$avg": "$OZONE" }
    } },
    { "$group": {
        "_id": "$year",
        "avgs": {
            "$push": {
                "k": {
                    "$let": {
                        "vars": { "monthsList": MONTHS },
                        "in": { "$arrayElemAt": ["$$monthsList", "$month"] }
                    }
                },
                "v": "$avgofozone"
            }
        }
    } },
    { "$replaceRoot": { 
        "newRoot": { 
            "$mergeObjects": [ 
                { "$arrayToObject": "$avgs" }, 
                "$$ROOT" 
             ] 
        } 
    } },
    { "$project": { "avgs": 0 } }
], (err, data) => {
    console.log("naresh:" +JSON.stringify(data));
    res.json(data);
})