Вы имеете в виду правильную идею, я бы лично начал агрегацию из коллекции answers
, так как $lookup
в этом контексте может стать очень дорогим.
db.answers.aggregate(
[
{
$group: {
_id: "$userIds",
answer1: {$push: "$answer1"},
answer2: {$push: "$answer2"},
answer3: {$push: "$answer3"},
}
},
{
addFields: {
answer1: {
$reduce: {
input: "$answer1",
initialValue: {great: 0, ok: 0, notgood: 0, bad: 0, total: 0},
in: {
total: {$add: ["$$value.total", 1]},
great: {$add: ["$$value.great", {$cond: [{$eq: ["$$this", "great"]}, 1, 0]}]},
ok: {$add: ["$$value.ok", {$cond: [{$eq: ["$$this", "ok"]}, 1, 0]}]},
notgood: {$add: ["$$value.notgood", {$cond: [{$eq: ["$$this", "Not good"]}, 1, 0]}]},
bad: {$add: ["$$value.bad", {$cond: [{$eq: ["$$this", "bad"]}, 1, 0]}]},
}
}
},
answer2: {
$reduce: {
input: "$answer2",
initialValue: {great: 0, ok: 0, notgood: 0, bad: 0, total: 0},
in: {
total: {$add: ["$$value.total", 1]},
great: {$add: ["$$value.great", {$cond: [{$eq: ["$$this", "great"]}, 1, 0]}]},
ok: {$add: ["$$value.ok", {$cond: [{$eq: ["$$this", "ok"]}, 1, 0]}]},
notgood: {$add: ["$$value.notgood", {$cond: [{$eq: ["$$this", "Not good"]}, 1, 0]}]},
bad: {$add: ["$$value.bad", {$cond: [{$eq: ["$$this", "bad"]}, 1, 0]}]},
}
}
},
answer3: {
$reduce: {
input: "$answer3",
initialValue: {great: 0, ok: 0, notgood: 0, bad: 0, total: 0},
in: {
total: {$add: ["$$value.total", 1]},
great: {$add: ["$$value.great", {$cond: [{$eq: ["$$this", "great"]}, 1, 0]}]},
ok: {$add: ["$$value.ok", {$cond: [{$eq: ["$$this", "ok"]}, 1, 0]}]},
notgood: {$add: ["$$value.notgood", {$cond: [{$eq: ["$$this", "Not good"]}, 1, 0]}]},
bad: {$add: ["$$value.bad", {$cond: [{$eq: ["$$this", "bad"]}, 1, 0]}]},
}
}
},
}
},
{
$addFields: {
ans: [
{
answer1: {
$arrayToObject: {
$filter: {
input: {
$map: {
input: {$objectToArray: "$answer1"},
as: "map_answer",
in: {
k: "$$map_answer.k", v: {$multiply: [{$divide: ["$$map_answer.v", "$answer1.total"]}, 100]}
}
}
},
as: "answer",
cond: {
$and: [
{$ne: ["$$answer.k", "total"]},
{$gt: ["$$answer.v", 0]}
]
}
}
}
}
},
{
answer2: {
$arrayToObject: {
$filter: {
input: {
$map: {
input: {$objectToArray: "$answer2"},
as: "map_answer",
in: {
k: "$$map_answer.k", v: {$multiply: [{$divide: ["$$map_answer.v", "$answer2.total"]}, 100]}
}
}
},
as: "answer",
cond: {
$and: [
{$ne: ["$$answer.k", "total"]},
{$gt: ["$$answer.v", 0]}
]
}
}
}
}
},
{
answer3: {
$arrayToObject: {
$filter: {
input: {
$map: {
input: {$objectToArray: "$answer3"},
as: "map_answer",
in: {
k: "$$map_answer.k", v: {$multiply: [{$divide: ["$$map_answer.v", "$answer3.total"]}, 100]}
}
}
},
as: "answer",
cond: {
$and: [
{$ne: ["$$answer.k", "total"]},
{$gt: ["$$answer.v", 0]}
]
}
}
}
}
}
]
}
},
{
$lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "user"
}
},
{
$unwind: "$user"
},
{
$project: {
_id: "$user._id",
userId: "$userId",
mail: "$user.mail",
ans: 1
}
}
]
)
Существует много манипуляций с данными кроме того, удаление 0 приводит к тому, что конвейер требует дополнительных шагов.