【问题标题】:MongoDB - Get Count of each unique value for each field in documentMongoDB - 获取文档中每个字段的每个唯一值的计数
【发布时间】:2021-02-09 13:23:38
【问题描述】:

过去两天我一直在寻找更好的解决方案,但没有提出任何建议。

基本上,我有一个包含如下文档的集合:

{ _id:5b5c92014fdd1f82c288530d
combine_id:1234
forty:4.65
broad:10.66
shuttle:4.18
threeCone:7.08
vert:40
bench:23
}

我希望能够在一个查询中获得每个字段的每个唯一值的总和。类似于:forty: [{time: 4.4, count: 7}, {time: 4.41, count: 11}, ...],但对于文档中的所有六个字段。我要做的是为每个字段创建一个值的钟形曲线。

我现在的查询如下,但我必须为每个字段单独运行它,所以我认为必须有一个更好、更优雅的解决方案。

db.combine.aggregate([
{   $group: {
        _id: {forty: '$forty'},
        count: { $sum: 1 }
} } ]);

希望这是可能的,我已经提供了足够的信息。谢谢

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    $facet 允许您在单个阶段内对同一组输入文档创建多方面聚合管道,因此您可以获得每个字段的计数,如下所示:

    db.combine.aggregate([
        { '$facet': {
            'forty':    [{ '$group': { '_id': '$forty', 'count': { '$sum': 1 } } }],
            'broad':    [{ '$group': { '_id': '$broad', 'count': { '$sum': 1 } } }],
            'shuttle':  [{ '$group': { '_id': '$shuttle', 'count': { '$sum': 1 } } }],
            'threeCone':[{ '$group': { '_id': '$threeCone', 'count': { '$sum': 1 } } }],
            'vert':     [{ '$group': { '_id': '$vert', 'count': { '$sum': 1 } } }],
            'bench':    [{ '$group': { '_id': '$bench', 'count': { '$sum': 1 } } }]
        } }
    ])
    

    要替换 _id 键,您需要为每个方面附加一个 $project 管道阶段,即

    [
        { '$group': { 
            '_id': <facet_key>, 
            'count': { '$sum': 1 } 
        } },
        { '$project': {
            '_id': 0,
            'time': '$_id',
            'count': 1
        } }
    ]
    

    稍微重构一下,如果这六个字段是已知且固定的,就可以动态创建管道如下:

    /* create the facet pipeline */
    const getFacetPipeline = key => ([
        { '$group': { 
            '_id': '$'+key, 
            'count': { '$sum': 1 } 
        } },
        { '$project': {
            '_id': 0,
            'time': '$_id',
            'count': 1
        } }
    ]);
    
    /* create the overall aggregate pipeline */
    const getAggregationPipeline = keys => (
        keys.reduce((acc, key) => {
            acc['$facet'][key] = getFacetPipeline(key);
            return acc;
        }, { '$facet': {} })
    );
    
    /* get the pipeline for the six fields */
    const pipeline = getAggregationPipeline([
        'forty', 
        'broad', 
        'shuttle', 
        'threeCone', 
        'vert', 
        'bench'
    ]);
    
    /* run the aggregate pipeline */
    db.combine.aggretate([pipeline]);
    

    【讨论】:

    • 这是完美的,谢谢。我不知道 $facet 运算符。也感谢为重构代码付出的额外努力,非常干净。
    • @ReeceLangerock 不用担心,总是乐于提供帮助 :)
    猜你喜欢
    • 2021-11-15
    • 2021-08-07
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多