使用MongoDB和Node.js无法获得计数数量

时间:2019-01-25 06:38:55

标签: node.js mongodb

我需要查询以通过使用MongoDB匹配数组中的某些值来按文档的键值获取总数。我在下面解释我的文档和输入。

dataArr=[
    {'login_id':9937229853,'location':'Delhi'},
    {'login_id':9937229854,'location':'JK'}
] 

我的文档如下。

  

反馈:

{
   login_id:9937229853,
   code: PTP,
   remark:'Hello'
 },
 {
   login_id:9937229853,
   code: PTP,
   remark:'Hii'
 },
{
   login_id:9937229853,
   code: CB,
   remark:'aaaaa'
 },
{
   login_id:9937229854,
   code: PTP,
   remark:'jjjjj'
 },
{
   login_id:9937229854,
   code: CB,
   remark:'dddd'
 }

以上是我的收藏。在这里,我需要根据数组中存在的每个用户输入login_id与文档进行匹配,并且将根据文档键和值获取总计数。我的预期输出如下。我在下面解释我的代码。

for(var i=0;i<dataArr.length;i++){
                    var login=dataArr[i]['login_id'];
                    //console.log('cdocs',dataArr[i]['login_id']);
                    Feedback.collection.count({login_id:dataArr[i]['login_id']},function(cerr,cdocs){
                       console.log('cdocs',login);
                        if (!cerr) {
                            if(cdocs > 0){
                              // console.log('login',cdocs);
                                db.collection.aggregate([
                                    {
                                        $match: {
                                            keywords: { $not: {$size: 0} }
                                        }
                                    },
                                    { $unwind: "$keywords" },
                                    {
                                        $group: {
                                            _id: {$toLower: '$keywords'},
                                            count: { $sum: 1 }
                                        }
                                    },
                                    {
                                        $match: {
                                            login_id: login
                                        }
                                    }
                                ])
                                .toArray((err,docs)=>{
                                    if (!err) {
                                     // console.log('count::',docs);
                                        finalArr=docs;

                                    }
                                })
                            }
                        }
                    })
                }
                var data={'status':'success','data':finalArr}
                res.send(data);

我需要如下所示的预期结果。

finalArr=[
    {'login_id':9937229853,'location':'Delhi','PTP':2,'CB':1,'remark':3},
    {'login_id':9937229854,'location':'JK','PTP':1,'CB':1,'remark':2},
]

但是使用我的代码,我得到了空白的输出。请帮助我解决此问题。

1 个答案:

答案 0 :(得分:0)

您可以通过单个聚合操作来完成所有这些操作。第一个管道阶段将是使用输入数组过滤集合中的文档。您可能需要将该数组仅映射到ID列表,以便使用$in查询运算符,即

const ids = dataArr.map(({ login_id }) => login_id)

然后可以在$match管道中用作

const match = { '$match': { 'login_in': { '$in': ids } } }

然后,下一个管道步骤将使用$group阶段通过login_id键将上述过滤的文档分组

const allGroup = { '$group': {
    '_id': {
        'login_id': '$login_id',
        'code': '$code',
        'remark': '$remark'
    },
    'count': { '$sum': 1 }
} }

另一个$group流水线阶段,用于获取备注作为键/值文档列表

const remarksGroup = { '$group': {
    '_id': {
        'login_id': '$_id.login_id',
        'code': '$_id.code'
    },
    'remarks': {
        '$push': {
            'k': '$_id.remark',
            'v': '$count'
        }
    },
    'count': { '$sum': 1 }
} }

获取与上面类似结构的代码计数

const codeGroup = { '$group': {
    '_id': '$_id.login_id',
    'codes': {
        '$push': {
            'k': '$_id.code',
            'v': '$count'
        }
    },
    'remarks': { '$first': '$remarks' }
} }

您将需要最后一个管道,以使用$arrayToObject将键/值对数组转换为对象,使用$mergeObjects将对象合并为一个对象,并使用{{3 }}:

const projections = { '$replaceRoot': {
    'newRoot': {
        '$mergeObjects': [
            { 'login_id': '$_id' },
            { '$arrayToObject': '$codes' },
            { '$arrayToObject': '$remarks' }
        ]
    }
} }

您的全部聚合流水线操作将是:

(async () => {
    try {
        const ids = dataArr.map(({ login_id }) => login_id)
        const match = { '$match': { 'login_in': { '$in': ids } } }
        const allGroup = { '$group': {
            '_id': {
                'login_id': '$login_id',
                'code': '$code',
                'remark': '$remark'
            },
            'count': { '$sum': 1 }
        } }
        const remarksGroup = { '$group': {
            '_id': {
                'login_id': '$_id.login_id',
                'code': '$_id.code'
            },
            'remarks': {
                '$push': {
                    'k': '$_id.remark',
                    'v': '$count'
                }
            },
            'count': { '$sum': 1 }
        } }
        const codeGroup = { '$group': {
            '_id': '$_id.login_id',
            'codes': {
                '$push': {
                    'k': '$_id.code',
                    'v': '$count'
                }
            },
            'remarks': { '$first': '$remarks' }
        } }
        const projections = { '$$replaceRoot': {
            'newRoot': {
                '$mergeObjects': [
                    { 'login_id': '$_id' },
                    { '$arrayToObject': '$codes' },
                    { '$arrayToObject': '$remarks' }
                ]
            }
        } }

        const result = await Feedback.aggregate([
            match,
            allGroup,
            remarksGroup,
            codeGroup,
            projections
        ])

        /* get the location key */
        const data = result.map(item => {
            const [{ location }, ...rest] = dataArr.filter(d => d.location_id === item.location_id)
            return { location, ...item }
        })

        console.log(data)
        res.send(data)

    } catch (err) {
        // handle error

    }
})()