MongoDB聚合,如何在组管道中addToSet数组的每个元素
Posted
技术标签:
【中文标题】MongoDB聚合,如何在组管道中addToSet数组的每个元素【英文标题】:MongoDB aggregate, how to addToSet each element of array in group pipeline 【发布时间】:2018-04-30 04:22:52 【问题描述】:我有包含标签字段的文档。这是一个简单的数组,里面有标签名称,里面没有对象也没有 _id。
像["Protocol", "Access", "Leverage", "Capability"]
这样的普通标签。
在我的小组管道中,我尝试了'selectedTags': $addToSet: '$tags'
之类的方法,但最终我得到了一个包含标签数组的数组。我对$push
也有同样的看法。
我尝试使用 $each
或 $pushAll
,但不支持它们作为我的 shell 告诉我的分组运算符。
有人可以帮我解决这个问题吗?
谢谢
编辑:
示例文档:
"_id" : "HWEdDGsq86x4ikDSQ",
"teamId" : "AdLizGnPuqbWNsFHe",
"ownerId" : "Qb5EigWjqn2t3bfxD",
"type" : "meeting",
"topic" : "Grass-roots hybrid knowledge user",
"fullname" : "Guidouil",
"startDate" : ISODate("2017-07-30T09:00:05.513Z"),
"shareResults" : true,
"open" : true,
"language" : "fr",
"tags" : [
"Protocol",
"Challenge",
"Artificial Intelligence",
"Capability"
],
"isDemo" : true,
"createdAt" : ISODate("2017-11-15T19:24:05.513Z"),
"participantsCount" : 10,
"ratersCount" : 10,
"averageRating" : 3.4,
"hasAnswers" : true,
"updatedAt" : ISODate("2017-11-15T19:24:05.562Z")
"_id" : "rXvkFndpXwJ6KAvNo",
"teamId" : "AdLizGnPuqbWNsFHe",
"ownerId" : "Qb5EigWjqn2t3bfxD",
"type" : "meeting",
"topic" : "Profit-focused modular system engine",
"fullname" : "Guidouil",
"startDate" : ISODate("2017-07-24T12:00:05.564Z"),
"shareResults" : true,
"open" : true,
"language" : "fr",
"tags" : [
"Initiative",
"Artificial Intelligence",
"Protocol",
"Utilisation"
],
"isDemo" : true,
"createdAt" : ISODate("2017-11-15T19:24:05.564Z"),
"participantsCount" : 33,
"ratersCount" : 33,
"averageRating" : 2.9393939393939394,
"hasAnswers" : true,
"updatedAt" : ISODate("2017-11-15T19:24:05.753Z")
聚合:
db.surveys.aggregate(
$match: query ,
$group:
'_id':
'year': $year: '$startDate' ,
'day': $dayOfYear: '$startDate' ,
,
'participants': $sum: '$ratersCount' ,
'rating': $avg: '$averageRating' ,
'surveys': $push: '$_id' ,
'selectedTags': $addToSet: '$tags' ,
'peoples': $addToSet: '$fullname' ,
,
$sort: _id: 1
);
然后我尝试将 selectedTags 更改为 $push: $each: '$tags'
或 $pushAll: '$tags'
但这不会执行:(
编辑 2:
在 javascript 中我是这样做的:
return Surveys.aggregate(
$match: query ,
$group:
_id: dateGroup,
participants: $sum: '$ratersCount' ,
rating: $avg: '$averageRating' ,
surveys: $push: '$_id' ,
selectedTags: $push: '$tags' ,
peoples: $addToSet: '$fullname' ,
,
$project:
_id: null,
selectedTags:
$reduce:
input: "$selectedTags",
initialValue: [],
in: $setUnion: ["$$value", "$$this"]
,
);
【问题讨论】:
你能展示你的尝试吗?它可能会对您想要实现的目标有所帮助。 【参考方案1】:Dannyxu 和 Alex Beck 的回答都有效,但仅在用于小组赛时部分有效。我需要将两者结合起来以获得单个平面标签数组的预期结果:
Model.aggregate()
.match( /** some query */ )
.group(
_id: '$teamId',
tagsSet: $push: '$tags' ,
numRecords: $sum: 1 ,
)
.project(
_id: 0,
numRecords: 1,
tagsSet:
$reduce:
input: '$tagsSet',
initialValue: [],
in: $setUnion: ['$$value', '$$this'] ,
,
,
)
.unwind( path: '$tagsSet' )
.group(
_id: null,
selectedTags: $addToSet: '$tagsSet' ,
numRecords: $sum: '$numRecords' ,
)
【讨论】:
【参考方案2】:您也可以使用$unwind 获取结果:
db.collection.aggregate([
$unwind: "$tags",
$group:
_id: null,
selectedTags: $addToSet: '$tags'
])
【讨论】:
谢谢,这个超级简单! 这是一个干净优雅的解决方案。在unwind tags
阶段,内存使用是一个真正的问题。【参考方案3】:
要在聚合管道中模拟$addToSet update operator with $each modifier 的功能,您可以在分组阶段使用$push 和在投影阶段使用$reduce + $setUnion 的组合。例如:
db.collection.aggregate([
$group:
_id: null,
selectedTags: $push: '$tags'
,
$project:
selectedTags: $reduce:
input: "$selectedTags",
initialValue: [],
in: $setUnion : ["$$value", "$$this"]
])
生成单个文档,其中包含来自selectedTags
数组中所有文档的不同标签列表。
【讨论】:
你说得对,我越来越接近我想要的,现在我有一个包含标签数组的数组。像这样:SelectedTags : [ ["Leverage", "Utilisation", "Capability", "Initiative"] ]
怎么样?答案中的 sn-p 返回一个平面标签数组。
我还需要其他字段,所以我这样做了
嗯,其他字段真的无所谓。只需将小组赛中的selectedTags: $push: '$tags'
替换为我发布的表达式即可。根据需要保留其余字段。
我尝试了这个gist.github.com/guidouil/147774bc36d0d62e1376eedaa1b54ff0,看起来它只是将原始组部分返回给我以上是关于MongoDB聚合,如何在组管道中addToSet数组的每个元素的主要内容,如果未能解决你的问题,请参考以下文章