Mongoose返回数组,每个元素的值旁边都有.count

Mongoose return array with .count of each element alongside each element value?

本文关键字:count 元素 数组 返回 Mongoose      更新时间:2023-09-26

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

我如何将结果构建为一个数组,其中包含每个搜索标记+有多少个故事具有该标记,其方式看起来像这样(将与模板引擎循环):

tags: [{tag: tag1, count: 4}, {tag: tag2,Count: 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

这里不是很清楚"tags"实际上是如何出现在您的文档中,它只是一个字段或数组中的单个值。无论如何,如果你打算计数标签,那么你最好使用聚合框架,而不是在代码中"后处理"你的.find()结果。

第一个使用"tags"作为单个字段值:

    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()操作,但也不确定您是否真的需要它。

如果"tags"实际上是一个数组,那么你需要做一些不同的事情,因为你需要从数组中提取匹配项以获得计数:

    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 操作符和其他操作符之前过滤数组来简化一点。

为了更清晰,我把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 });
        }
    );

它的优点是在调用 $unwind 之前从数组中删除你不想要的"标签",这可以根据有多少数组元素来加速匹配。

当然,虽然上面的示例在获取文档计数方面与第一个示例有所不同,但如果您更喜欢组合的结果,您仍然可以将其包含在一个额外的分组中:

    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] );
        }
    );

同样,不需要像 $size 这样的操作符,也可以通过不同的分组来获得单个结果中的totalCount,甚至不需要 $addToSet

但是总的方向是,如果你要计算"标签",这是你基本上想要去的地方,因为你可以让服务器为你做这项工作