需求
有时候,我们需要在查询结果中将某个字段(数组)合并起来,返回一个数组即可。
例子
假设集合user:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| { "_id" : ObjectId("5eb6bb5bc95fdd10d0f6d21e"), "name" : "小明", "education" : "本科", "experiences" : [ { "profession" : "程序员", "ability" : [ "java", "nodejs", "golang" ] } ] } // ---------------------------------------------- { "_id" : ObjectId("5eb6bbdbc95fdd10d0f6d220"), "name" : "小红", "education" : "本科", "experiences" : [ { "profession" : "销售", "ability" : [ "沟通", "财务计算" ] }, { "profession" : "采购员", "ability" : [ "英语", "统计" ] } ] } // ---------------------------------------------- { "_id" : ObjectId("5eb6bdbbc95fdd10d0f6d23f"), "name" : "小三", "education" : "大专", "experiences" : [ { "profession" : "行政助理", "ability" : [ "英语" ] } ] }
|
接下来我想查询出所有学历为“本科”的阅历(experiences)列表,并把它们合并成一个数组返回,如:
1 2 3 4 5 6 7 8
| { "_id" : "1", "experiences" : [ { "profession" : "销售", "ability" : ["沟通", "财务计算"] }, { "profession" : "采购员", "ability" : ["英语", "统计"]}, { "profession" : "程序员", "ability" : ["java", "nodejs", "golang"]} ] }
|
实现
使用Aggregate来实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| db.getCollection("user").aggregate( [ { "$match" : { "education" : "本科" } }, { "$group" : { "_id" : "1", "experiences" : { "$addToSet" : "$experiences" } } }, { "$project" : { "experiences" : { "$reduce" : { "input" : "$experiences", "initialValue" : [], "in" : { "$concatArrays" : ["$$value", "$$this"] } } } } } ] );
|
说明:
- $match: 选择器,筛选的条件,这里查询出学历(education)为本科的数据。
- $group: 相当于sql中的group by, 例子中的”_id”只是用于分组的标识,“experiences“设置分组返回到哪个字段上,相当于as。
- $addToSet: 不重复添加到数组。
到这里,会把学历为“本科”的阅历全部查出来,数据是这样子:
1 2 3 4 5 6 7 8 9 10 11 12
| { "_id" : "1", "experiences" : [ [ {"profession" : "销售", "ability" : [ "沟通", "财务计算" ]}, {"profession" : "采购员", "ability" : [ "英语", "统计" ]} ], [ {"profession" : "程序员", "ability" : ["java", "nodejs", "golang"]} ] ] }
|
但这还不是我们要的结果,使用$project再次处理,所有experiences追加
。
1 2 3 4 5 6 7 8 9 10 11
| { "$project" : { "experiences" : { "$reduce" : { "input" : "$experiences", "initialValue" : [], "in" : { "$concatArrays" : ["$$value", "$$this"] } } } } }
|
说明:
- $project: 接受一个文档,该文档可以指定包含字段、禁止显示id字段、添加新字段以及重置现有字段的值。或者,可以指定排除字段。
- $reduce:将”in”里的表达式应用到”input”数组里,并将它们合并成一个数组。
- “in”里面的表达式可以很灵活的对数组操作,这里用的$concatArrays将experiences[]字段里的元素连接起来。
最后结果:
1 2 3 4 5 6 7 8
| { "_id" : "1", "experiences" : [ { "profession" : "销售", "ability" : ["沟通", "财务计算"] }, { "profession" : "采购员", "ability" : ["英语", "统计"]}, { "profession" : "程序员", "ability" : ["java", "nodejs", "golang"]} ] }
|
参考
https://docs.mongodb.com/manual/reference/operator/aggregation/reduce/