Mongoose返回数组,每个元素的.count与每个元素值一起?

时间:2014-06-09 14:58:08

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

现在,这个expressJS调用将逗号分隔的值提供给导致.find的mongoose .count,但是分别返回计数和值。

我如何将结果构造成一个包含每个搜索标记的数组+具有该标记的故事数量的计数,其方式看起来像这样(用模板引擎循环):

  

标签:[{tag:tag1,count:4},{tag:tag2,   数:2}]

这里是快递/猫鼬:

router.route('/tag/:tags')

    // get the list of tags for userGenerated tags
    // accessed by GET at http://localhost:4200/api/v1/tag/tag1,tag2
    .get(function(req, res) {

        var tags = req.params.tags.split(',');

        console.log(tags); // ['tag1', 'tag2']

        Story.count( { tags: { $in: tags } }, function (err, count) {

            if (err)
                res.send(err);

            console.log('there is/are %d story(ies) with this/these tag(s)', count);

            if (count >= 1) {

                Story.find( { tags: { $in: tags } }, 'tags', function(err, stories) {

                    if (err)
                        res.send(err);

                    res.json(storytags);

                }); // find and return tags of stories

            } // if count >= 1

            if (count < 1) {

                res.json({ message: count + ' results' });

            } // if count < 1 

        }); // .count

    }); // get list of tags

1 个答案:

答案 0 :(得分:2)

这里不太清楚&#34;标签&#34;实际上出现在您的文档中,它只是字段中的单个值或数组中的单个值。无论如何,如果你打算计算标签,那么你最好使用aggregation framework而不是&#34;后处理&#34;您的.find()会产生代码。

首先使用&#34;标签&#34;作为单个字段值:

    Story.aggregate(
        [
            // Match the documents with tags
            { "$match": { "tags": { "$in": tags } }},

            // Group the tags with counts
            { "$group": {
                "_id": "$tags",
                "count": { "$sum": 1 }
            }},

            // Group to single array with total count
            { "$group": {
                "_id": null,
                "tags": { 
                    "$push": {
                        "tag": "$_id",
                        "count": "$count"
                    }
                },
                "totalCount": { "$sum": "$count" }
            }},

            // Project to remove the _id
            { "$project": {
                "_id": 0,
                "tags": 1,
                "totalCount": 0
            }}
        ],
        function(err,result) {

            if (err)
                res.send(err);

            res.json( result[0] );

        }
    );

这几乎封装了整个列表,因此不需要额外的.count()操作,但也不确定是否真的需要它。

&#34;标签&#34;实际上是一个数组然后你需要做一些不同的事情,因为你需要从数组中提取你的匹配来获得计数:

    Story.aggregate(
        [
            // Match the documents with tags
            { "$match": { "tags": { "$in": tags } }},

            // Unwind the array
            { "$unwind": "$tags" },

            // Actually match the tags within the now unwound array
            { "$match": { "tags": { "$in": tags } }},

            // Group by each tag
            { "$group": {
                "_id": "$tags",
                "count": { "$sum": 1 }
            }},

            // Rename the _id for your output
            { "$project": {
               "_id": 0,
               "tag": "$_id",
               "count": 1
            }}

        ],
        function(err,result) {

            if (err)
                res.send(err);

            res.json({ "totalCount": count, "tags": result });

        }
    );

或者使用MongoDB 2.6或更高版本,您可以通过使用$unwind运算符和其他人$map数组$unwind之前过滤数组来简化一点。

为了清晰起见,我只是在这里展开tags

    Story.aggregate(
        [
            // Match the documents with tags
            { "$match": { "tags": { "$in": ["tag1","tag2" } }},


            // Filter the array for matches
            { "$project": {
                "tags": {
                   "$setDifference": [
                       { 
                           "$map": {
                               "input": "$tags",
                               "as": "el",
                               "in": {
                                   "$cond": [
                                       { "$or": [
                                           { "$eq": ["$$el", "tag1" ] },
                                           { "$eq": ["$$el", "tag2" ] },
                                       ]},
                                       "$$el",
                                       false
                                   ]
                               }
                           }
                       },
                       [false]
                   ]
                }
            }},

            // Unwind the array already filtered
            { "$unwind": "$tags" },

            // Group by each tag
            { "$group": {
                "_id": "$tags",
                "count": { "$sum": 1 }
            }},

            // Rename the _id for your output
            { "$project": {
               "_id": 0,
               "tag": "$_id",
               "count": 1
            }}

        ],
        function(err,result) {

            if (err)
                res.send(err);

            res.json({ "totalCount": count, "tags": result });

        }
    );

其优点是删除了&#34;标签&#34;在调用$size之前你不想从数组中获取,这可以加速匹配,具体取决于有多少数组元素。

当然,虽然以上示例与获取文档计数的第一个示例不同,但如果您更喜欢合并后的结果,仍可以使用一些额外的分组:

    Story.aggregate(
        [
            // Match the documents with tags
            { "$match": { "tags": { "$in": ["tag1","tag2" } }},


            // Filter the array for matches
            { "$project": {
                "tags": {
                   "$setDifference": [
                       { 
                           "$map": {
                               "input": "$tags",
                               "as": "el",
                               "in": {
                                   "$cond": [
                                       { "$or": [
                                           { "$eq": ["$$el", "tag1" ] },
                                           { "$eq": ["$$el", "tag2" ] },
                                       ]},
                                       "$$el",
                                       false
                                   ]
                               }
                           }
                       },
                       [false]
                   ]
                }
            }},

            // Unwind the array already filtered
            { "$unwind": "$tags" },

            // Group by each tag
            { "$group": {
                "_id": "$tags",
                "count": { "$sum": 1 },
                "docs": { "$addToSet": "$_id" }
            }},

            // Group to a single array response
            { "$group": {
                "_id": null,
                "tags": {
                    "$push": {
                        "tag": "$_id",
                        "count": "$count"
                    }
                },
                "totalCount": { "$sum": { "$size": "$docs" } }
            }

            // Rename the fields for your output
            { "$project": {
               "_id": 0,
               "tags": 1,
               "count": 1,
               "totalCount"
            }}

        ],
        function(err,result) {

            if (err)
                res.send(err);

            res.json( result[0] );

        }
    );

再次,获得&#34; totalCount&#34;在一个单一的结果中,可以在没有$addToSet之类的运算符的帮助下完成,实际上没有{{3}}的分组不同。

但是这里的总体方向是,如果您正在计算&#34;标签&#34;,那么您基本上想要去的地方,因为您可以让服务器为您完成工作。