一尘不染

填写记录中的缺失日期

node.js

我有一个收藏ProductViews

产品浏览

{
    productId: '5b8c0f3204a10228b00a1745,
    createdAt: '2018-09-07T17:18:40.759Z',
}

我有一个查询,用于获取特定产品的每日视图。

询问

ProductView.aggregate([
    { $match: { productId } },
    { $project: { day: { $substr: ["$createdAt", 0, 10] } } },
    {
        $group: {
            _id: "$day",
            count: { $sum: 1 },
            time: { $avg: "$createdAt" },
        }
    },
    { $sort: { _id: 1 } },
    {
        $project: {
            date: '$_id',
            views: '$count',
        },
    },
]).exec((err, result) => ...)

当前结果

[
    { date: '2018-09-01', views: 1 },
    { date: '2018-09-02', views: 3 },
    { date: '2018-09-04', views: 2 },
    { date: '2018-09-05', views: 5 },
    // ...
]

问题

问题是,这种聚合不会{ date: '2018-09-03', views: 0 }在有0视图的几天内返回。这会导致数据显示不正确:在此处输入图片说明

结果应该看起来像

[
    { date: '2018-09-01', views: 1 },
    { date: '2018-09-02', views: 3 },
    { date: '2018-09-03', views: 0 },
    { date: '2018-09-04', views: 2 },
    { date: '2018-09-05', views: 5 },
    // ...
]

PS:最好输入开始和结束日期以基于此范围输出结果


阅读 304

收藏
2020-07-07

共1个答案

一尘不染

您需要几个额外的步骤来返回默认值。首先,你需要使用$group_id设置为null收集所有结果中的一个文件内。然后,您可以将$
map
与一组天作为输入。在其中,$map您可以使用$
indexOfArray
查找当前结果集中是否存在该日期。如果是(index != -1),则可以返回该值,否则需要返回默认子文档,views并将其设置为0。然后,您可以使用$
unwind
来获取文档列表,并使用$
replaceRoot
来将嵌套提升stats到顶层。

ProductView.aggregate([
    { $match: { productId: '5b8c0f3204a10228b00a1745' } },
    { $project: { day: { $substr: ["$createdAt", 0, 10] } } },
    {
        $group: {
            _id: "$day",
            count: { $sum: 1 },
            time: { $avg: "$createdAt" },
        }
    },
    { $sort: { _id: 1 } },
    {
        $project: {
            date: '$_id',
            views: '$count',
        },
    },
    {
        $group: {
            _id: null,
            stats: { $push: "$$ROOT" }
        }
    },
    {
        $project: {
            stats: {
                $map: {
                    input: [ "2018-09-01", "2018-09-02", "2018-09-03", "2018-09-04", "2018-09-05" ],
                    as: "date",
                    in: {
                        $let: {
                            vars: { dateIndex: { "$indexOfArray": [ "$stats._id", "$$date" ] } },
                            in: { 
                                $cond: {
                                    if: { $ne: [ "$$dateIndex", -1 ] },
                                    then: { $arrayElemAt: [ "$stats", "$$dateIndex" ] },
                                    else: { _id: "$$date", date: "$$date", views: 0 }
                                } 
                            }
                        }
                    }
                }
            }
        }
    },
    {
        $unwind: "$stats"
    },
    {
        $replaceRoot: {
            newRoot: "$stats"
        }
    }
]).exec((err, result) => ...)

您可以使用简单循环在应用程序逻辑中生成静态日期列表。我相信在MongoDB中也可以(使用$
range
),但这可能会使此聚合管道复杂化。让我知道您是否满意,或者想尝试在MongoDB中生成该日期数组。

2020-07-07