【问题标题】:Multiple $unwind and $group in mongo querymongo 查询中的多个 $unwind 和 $group
【发布时间】:2019-11-07 03:35:18
【问题描述】:

有点挣扎于 mongodb 查询。我的 mongo 数据库具有以下结构:

name: String
test: String
competences: [{name: String, code: String, value: Float}]
subcompetences: [{name: String, code: String, value: Float}]

我的查询如下所示:

async function getAggregatedDataForCompetences(filter, category) {
    return await getCollection('competences').aggregate([
    {$match: { $or: filter }},
    {$unwind:  "$competences" },
    {$group: {
        _id: "$_id",
        code:  { $first: "$competences.code" },
        name:  { $first: "$competences.name"},
        avgValue: { $avg: "$competences.value" },
        subcompetences:  { $first: "$subcompetences"},
        }
    },
    {$unwind:  "$subcompetences" },
    {$group: {
        _id: "$subcompetences.code",
        code:  { $first: "$subcompetences.code" },
        name:  { $first: "$subcompetences.name"},
        avgValue: { $avg: "$subcompetences.value" },
    }}
    ]).toArray();
}

我想要做的是展开所有元素的第一个(能力)数组,将它们分组并计算每个项目的平均值。对以下对象的子能力数组重复相同的过程。结果,我只得到最后一个子能力数组的平均值。你知道我怎样才能达到以下结果:

{
   competences: [{name: String, code: String, avgValue: Float}],
   subcompetences: [{name: String, code: String, avgValue: Float}]
}

【问题讨论】:

  • 为什么competencies$_id 分组,而subcompetencies 在两者中都被``$code? Typo? I think you want to group by $code` 分组,不是吗?

标签: javascript mongodb


【解决方案1】:

$facet 救援——“多组”运算符。给定这样的输入:

var r =
[
{
    "_id" : 0,
    "name": "N1",
    "competences": [
{name: "AAA", code: "A", value: 1.1},
{name: "BBB", code: "B", value: 2.2},
{name: "CCC", code: "C", value: 3.3}
                    ],
    "subcompetences": [
{name: "DDD", code: "D", value: 4.4},
{name: "EEE", code: "E", value: 5.5},
{name: "FFF", code: "F", value: 6.6}
]
        }

,{
    "_id" : 1, "name": "N2",
    "competences": [
{name: "AAA", code: "A", value: 9.9},
{name: "BBB", code: "B", value: 8.8},
{name: "KKK", code: "K", value: 11.11}
                    ],
    "subcompetences": [
{name: "FFF", code: "F", value: 4.9},
{name: "GGG", code: "G", value: 6.7}
]
        }
 ];

然后$facet 将允许您“并行”进行两组。实际上,您可以同时执行两个或多个完整的管道(有一些限制):

db.foo.aggregate([
{$facet: {
  "avg_competences": [
      {$unwind: "$competences"}
      ,{$group: {_id: "$competences.code",
           name: {$first: "$competences.name"},
           count: {$sum: 1},
           avgval: {$avg: "$competences.value"},
        }}
           ]

  ,"avg_subcompetences": [
      {$unwind: "$subcompetences"}
      ,{$group: {_id: "$subcompetences.code",
           name: {$first: "$subcompetences.name"},
           count: {$sum: 1},
           avgval: {$avg: "$subcompetences.value"},
        }}
           ]
    }
}

// The output of the stage above will be a *single* doc with two fields, 
// avg_competence and avg_subcompetences.  Let's add more fields to this doc!
,{$addFields: {N: {$reduce: {
                input: {$concatArrays: ["$avg_competences","$avg_subcompetences"]},
                initialValue: 0,
                in:{$sum: [ "$$value", "$$this.count"]}
            }}
    }}


   ]);

屈服:

{
    "avg_competences" : [
        {
            "_id" : "K",
            "name" : "KKK",
            "count" : 1,
            "avgval" : 11.11
        },
        {
            "_id" : "C",
            "name" : "CCC",
            "count" : 1,
            "avgval" : 3.3
        },
        {
            "_id" : "B",
            "name" : "BBB",
            "count" : 2,
            "avgval" : 5.5
        },
        {
            "_id" : "A",
            "name" : "AAA",
            "count" : 2,
            "avgval" : 5.5
        }
    ],
    "avg_subcompetences" : [
        {
            "_id" : "G",
            "name" : "GGG",
            "count" : 1,
            "avgval" : 6.7
        },
        {
            "_id" : "F",
            "name" : "FFF",
            "count" : 2,
            "avgval" : 5.75
        },
        {
            "_id" : "E",
            "name" : "EEE",
            "count" : 1,
            "avgval" : 5.5
        },
        {
            "_id" : "D",
            "name" : "DDD",
            "count" : 1,
            "avgval" : 4.4
        }
    ],
    "N" : 11
}

【讨论】:

  • 完美,非常感谢。既然你似乎精通这个话题,我想再问你一个问题。如果我想在最终结果中添加对象怎么办。例如,让我们计算应用过滤器的对象总数:count: { $sum : 1 },所以最终对象看起来像这样:{ general: {count: 1234},competences: [{name: String, code: String , avgValue: Float}], 子能力: [{name: String, code: String, avgValue: Float}] }
  • 您是指avg_competencesavg_subcompetences 的总数,即上例中的11?另外:不要对投票箭头感到害羞,也不要让这成为一个公认的答案。 :-)
  • 答案扩展为包括向输出文档添加总计字段。
猜你喜欢
  • 2019-10-02
  • 1970-01-01
  • 1970-01-01
  • 2018-04-12
  • 2019-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-23
  • 1970-01-01
相关资源
最近更新 更多