$在聚合框架中展开对象

Bre*_*mas 30 mongodb aggregation-framework

在MongoDB聚合框架中,我希望在对象(即JSON集合)上使用$ unwind运算符.看起来这不可能,是否有解决方法?有计划实施吗?

例如,从聚合文档中获取文章集合.假设有一个额外的字段"评级"是来自用户 - >评级的地图.你能算出每个用户的平均评分吗?

除此之外,我对聚合框架非常满意.

更新:这是每个请求的JSON集合的简化版本.我正在存储基因组数据.我不能真正使基因型成为一个数组,因为最常见的查找是获取随机人的基因型.

variants: [

    {
        name: 'variant1', 
        genotypes: {

            person1: 2,
            person2: 5,
            person3: 7,

        }
    }, 

    {
        name: 'variant2', 
        genotypes: {

            person1: 3,
            person2: 3,
            person3: 2,

        }
    }

]
Run Code Online (Sandbox Code Playgroud)

Asy*_*sky 29

您无法使用聚合框架执行您正在描述的计算类型 - 并且不是因为没有$unwind非数组的方法.即使person:value对象是数组中的文档,$unwind也无济于事.

"分组依据"功能(无论是在MongoDB中还是在任何关系数据库中)都是对字段或列的值完成的.我们根据另一个字段的值按字段值和sum/average/etc进行分组.

简单示例是您建议的变体,评级字段添加到示例文章集合中,但不是作为从用户到评级的映射,而是作为这样的数组:

{ title : title of article", ...
  ratings: [
         { voter: "user1", score: 5 },
         { voter: "user2", score: 8 },
         { voter: "user3", score: 7 }
  ]
}
Run Code Online (Sandbox Code Playgroud)

现在你可以用以下方法聚合:

[ {$unwind: "$ratings"},
  {$group : {_id : "$ratings.voter", averageScore: {$avg:"$ratings.score"} } } 
]
Run Code Online (Sandbox Code Playgroud)

但是这个结构如你所描述的那样看起来像这样:

{ title : title of article", ...
  ratings: {
         user1: 5,
         user2: 8,
         user3: 7
  }
}
Run Code Online (Sandbox Code Playgroud)

甚至这个:

{ title : title of article", ...
  ratings: [
         { user1: 5 },
         { user2: 8 },
         { user3: 7 }
  ]
}
Run Code Online (Sandbox Code Playgroud)

即使你能做到$unwind这一点,也没有什么可以聚合在这里.除非您知道所有可能的密钥(用户)的完整列表,否则您无法做到这一点.[*]

一个类似的关系数据库模式,你将拥有:

CREATE TABLE T (
   user1: integer,
   user2: integer,
   user3: integer
   ...
);
Run Code Online (Sandbox Code Playgroud)

这不是将要做的,而是我们会这样做:

CREATE TABLE T (
   username: varchar(32),
   score: integer
);
Run Code Online (Sandbox Code Playgroud)

现在我们使用SQL聚合:

select username, avg(score) from T group by username;

MongoDB有一个增强请求,可能允许您将来在聚合框架中执行此操作 - 将值投影到键的能力,反之亦然.同时,总有map/reduce.

[*]还有就是要做到这一点,如果你知道所有的唯一键(你可以找到类似的方法都是唯一的密钥的复杂的方式),但如果你知道所有的钥匙,你可能也只是运行的查询序列db.articles.find({"ratings.user1":{$exists:true}},{_id:0,"ratings.user1":1})每个userX的表单将返回所有评级,您可以简单地对它们求和并进行平均,而不是进行聚合框架所需的非常复杂的投影.


Adr*_*ian 8

从3.4.4开始,您可以使用$ objectToArray将对象转换为数组

请参阅:https: //docs.mongodb.com/manual/reference/operator/aggregation/objectToArray/