在mongoDB / Mongoose上使用查找和聚合来获取数据

时间:2018-08-07 12:09:17

标签: javascript node.js mongodb express mongoose

我正在研究一个node.js项目,以使用前端的图表显示一些数据。

我的路线上有以下两个查询:

    atendimentos.find({})
        .then(atendimentos => {
            final = atendimentos.filter(atendimentos => atendimentos.status === 'F')
            testeea = atendimentos.filter(atendimentos => atendimentos.status === 'EA')
            res.render('home', {user: req.user, fin: final.length, ea: testeea.length});
            //Funciona
            console.log(final.length)
        })
        .catch(err => console.error(err));

    atendimentos.aggregate([
        { $project:
                { _id: "$month",
                    year: {$year: "$date" },
                    month: { $month: "$date"},
                    amount: 1
                }
        },
        { $group:
                { _id: { year: "$year", month: ("$month")},
                    sum: { $sum: 1}
                }
        }]).exec(function(error, items){
        if(error){return next(error);}

        console.log(items);
    });

编辑1:

所以,输入数据...我想我没有任何数据,因为我实际上是通过查询从数据库中获取所有内容的。我期望的数据是我在图表上呈现的状态为F或EA的文档/对象。

该数据库大约有8.5k个文档,F返回了8041个文档,EA返回了351,这是一个简单的数组,其编号在我的路线上使用.length返回。这些数字显示在图表上。

现在,与聚合部分有关,我正在尝试使用集合制作一张表。我打算显示每月的支持电话(atendimentos)数量。它实际上是在记录正确的数据,如下所示:

[ { _id: { year: 2018, month: 6 }, sum: 4005 },
  { _id: { year: 2018, month: 7 }, sum: 43 },
  { _id: { year: 2018, month: 5 }, sum: 3996 },
  { _id: { year: 2018, month: 4 }, sum: 434 } ]

我想使用这些数据在我的视图上呈现表格。

编辑结束1

编辑2

router.get('/home', isAuthenticated, async (req, res, next) =>  {

    let final;
    let testeea;

    atendimentos.find({})
        .then(atendimentos => {
            final = atendimentos.filter(atendimentos => atendimentos.status === 'F')
            testeea = atendimentos.filter(atendimentos => atendimentos.status === 'EA')

            res.render('home', {user: req.user, fin: final.length, ea: testeea.length});
            //Funciona
            console.log(final.length)
        })
        .catch(err => console.error(err));

所以,这是路线,另一部分只是我尝试做的聚合查询和右括号。如您所见,我得到了数据,并使用Array.filter来过滤获取的结果,状态为F或EA。

它返回我数组的长度,因此它计算每个字母的状态数。此数字在图表中呈现,因为我将其以fin:final.length和ea:testeea.length的形式发送到前端。这里没有格式化的数据或类似的东西。这样就可以了。

关于聚合部分,该部分每月返回电话,我只想使用月和年的电话数。在这一部分中,我期望的数据如下:[ { _id: { year: 2018, month: 6 }, sum: 4005 }

我希望我可以像获取fin和ea一样获取数据,使用.length进行计数并将其放入视图中。

编辑结束2

两者都恰好返回了我需要的东西,问题是我不能只将聚合查询放在find查询之前,然后将item:项目添加到render方法。我想知道如何执行这些查询以显示与我在这两个查询中获取的相同的内容。预先感谢!

1 个答案:

答案 0 :(得分:1)

MongoDB Server 3.2及更低版本

您需要运行两个聚合查询并合并结果中的对象。这可以通过多种方式完成,但可以向您展示Promise方式和async / await方式。

1。使用承诺

router.get('/home', isAuthenticated, (req, res, next) =>  {
    const counts = atendimentos.aggregate([
        { '$group': { 
            '_id': null,             
            'fin': {
                '$sum': {
                    '$cond': [ { '$eq': [ '$status', 'F' ] }, 1, 0 ]
                }
            },
            'ea': {
                '$sum': {
                    '$cond': [ { '$eq': [ '$status', 'EA' ] }, 1, 0 ]
                }
            }
        } }
    ]).exec();

    const monthly = atendimentos.aggregate([
        { '$group': { 
            '_id': { 
                'year': { '$year': '$date' },
                'month': { '$month': '$date' }
            },
            'sum': { '$sum':  1 }
        } },
        {  '$group': {
            '_id': null,
            'back': { '$push':  '$$ROOT' }
        } },
    ]).exec();

    Promise.all([ counts, monthly ]).then(([ counts, monthly ]) => {
        const statusData = counts[0];
        const monthlyData = monthly[0];

        const data = {...statusData, ...monthlyData, user: req.user};
        console.log(JSON.stringify(data, null, 4));

        res.render('home', data);
    }).catch(err => next(err));

});

2。使用异步/等待

router.get('/home', isAuthenticated, async (req, res, next) =>  {
    try {
        const counts = await atendimentos.aggregate([
            { '$group': { 
                '_id': null,             
                'fin': {
                    '$sum': {
                        '$cond': [ { '$eq': [ '$status', 'F' ] }, 1, 0 ]
                    }
                },
                'ea': {
                    '$sum': {
                        '$cond': [ { '$eq': [ '$status', 'EA' ] }, 1, 0 ]
                    }
                }
            } }
        ]).exec();

        const monthly = await atendimentos.aggregate([
            { '$group': { 
                '_id': { 
                    'year': { '$year': '$date' },
                    'month': { '$month': '$date' }
                },
                'sum': { '$sum':  1 }
            } },
            {  '$group': {
                '_id': null,
                'back': { '$push':  '$$ROOT' }
            } },
        ]).exec();

        const statusData = counts[0];
        const monthlyData = monthly[0];

        const data = {...statusData, ...monthlyData, user: req.user};
        console.log(JSON.stringify(data, null, 4));

        res.render('home', data);
    } catch (err) {
        next(err);
    }
});

MongoDB Server 3.4.4及更高版本

聚合管道还可以处理过滤,您只需要使用 $facet 管道步骤即可,该步骤能够在同一阶段的同一组输入文档上处理多个聚合管道。每个子管道在输出文档中都有自己的字段,其结果存储为文档数组。

考虑运行以下管道:

atendimentos.aggregate([
    { '$facet': {
        'counts': [
            { '$group': { 
                '_id': null,             
                'fin': {
                    '$sum': {
                        '$cond': [ { '$eq': [ '$status', 'F' ] }, 1, 0 ]
                    }
                },
                'ea': {
                    '$sum': {
                        '$cond': [ { '$eq': [ '$status', 'EA' ] }, 1, 0 ]
                    }
                }
            } }
        ],
        'monthly': [
            { '$group': { 
                '_id': { 
                    'year': { '$year': '$date' },
                    'month': { '$month': '$date' }
                },
                'sum': { '$sum':  1 }
            } },
            {  '$group': {
                '_id': null,
                'items': { '$push':  '$$ROOT' }
            } },
        ]
    } },
    { '$replaceRoot': { 
        'newRoot': { 
            '$mergeObjects': { 
                '$concatArrays': ['$counts', '$monthly'] 
            } 
        } 
    } }
]).exec((err, results) => {
    const data = results[0];
    console.log(data);

    res.render('home', { user: req.user, ...data });
})