这可以通过一组数组运算符一起工作以产生所需的效果来完成。
您基本上需要一个操作来创建您需要的计数的键/值对数组。然后将其转换为哈希映射。键值对数组本质上是一个映射,它是通过遍历multipleOptions数组并检查答案数组中匹配的元素的大小来构造的。
TLDR;
您需要运行的最终管道如下:
db.collection.aggregate([
{ "$project": {
"result": {
"$arrayToObject": {
"$map": {
"input": { "$range": [ 0, { "$size": "$multipleOptions" } ] },
"as": "idx",
"in": {
"$let": {
"vars": {
"k": {
"$arrayElemAt": [
"$multipleOptions",
"$$idx"
]
},
"v": {
"$size": {
"$filter": {
"input": "$answers",
"as": "ans",
"cond": {
"$eq": [
"$$ans",
{
"$arrayElemAt": [
"$multipleOptions",
"$$idx"
]
}
]
}
}
}
}
},
"in": { "k": "$$k", "v": "$$v" }
}
}
}
}
}
} }
])
为了逐步演示这一点,让我们在聚合操作中创建一个附加字段,该字段将是相应数组元素的计数的数组。我们需要类似的东西
{
"questionType": "multiple",
"multipleOptions": ["awful", "bad", "soso", "good", "excellent"],
"answersCount": [1, 3, 2, 1, 1],
"answers": ["bad", "bad", "good", "soso", "bad", "excellent", "awful", "soso"]
}
为了得到这个,我们需要一种方法来循环multipleOptions遍历每个选项,迭代answers数组,过滤它并计算过滤数组中元素的数量。伪算法如下:
answersCount = []
for each elem in ["awful", "bad", "soso", "good", "excellent"]:
filteredAnswers = [<answers array containing only elem>]
count = filteredAnswers.length
answersCount.push(count)
在 mongo 中,过滤部分可以$filter在answers数组上完成,元素可以用$arrayElemAt
{
"$filter": {
"input": "$answers",
"as": "ans",
"cond": {
"$eq": [
"$$ans",
{ "$arrayElemAt": [ "$multipleOptions", "$$idx" ] }
]
}
}
}
$size使用上述表达式得出计数
{
"$size": {
"$filter": {
"input": "$answers",
"as": "ans",
"cond": {
"$eq": [
"$$ans",
{ "$arrayElemAt": [ "$multipleOptions", "$$idx" ] }
]
}
}
}
}
为了获得外循环,我们可以使用$rangeand $mapas
{
"$map": {
"input": { "$range": [ 0, { "$size": "$multipleOptions" } ] },
"as": "idx",
"in": {
"$let": {
"vars": {
"v": {
"$size": {
"$filter": {
"input": "$answers",
"as": "ans",
"cond": {
"$eq": [
"$$ans",
{ "$arrayElemAt": [ "$multipleOptions", "$$idx" ] }
]
}
}
}
}
},
"in": "$$v"
}
}
}
}
这将answersCount在以下聚合操作中产生
db.collection.aggregate([
{ "$addFields": {
"answersCount": {
"$map": {
"input": { "$range": [ 0, { "$size": "$multipleOptions" } ] },
"as": "idx",
"in": {
"$let": {
"vars": {
"v": {
"$size": {
"$filter": {
"input": "$answers",
"as": "ans",
"cond": {
"$eq": [
"$$ans",
{ "$arrayElemAt": [ "$multipleOptions", "$$idx" ] }
]
}
}
}
}
},
"in": "$$v"
}
}
}
}
} }
])
然后要获得所需的输出,您需要answersCount成为键/值对数组,即
{
"answersCount": [
{ "k": "awful", "v": 1},
{ "k": "bad", "v": 3},
{ "k": "soso", "v": 2},
{ "k": "good", "v": 1},
{ "k": "excellent", "v": 1}
],
}
当你应用$arrayToObject上面的表达式时,即
{ "$arrayToObject": {
"answersCount": [
{ "k": "awful", "v": 1},
{ "k": "bad", "v": 3},
{ "k": "soso", "v": 2},
{ "k": "good", "v": 1},
{ "k": "excellent", "v": 1}
],
} }
你得到
{
"awful" : 1,
"bad" : 3,
"soso" : 2,
"excellent" : 1,
"good" : 1
}