I have a collection called notifications
that has 2 fields (for simplicity):
targets
is an array of stringsuserReads
is an array of object{userId, readAt}
Example :
{
targets: ['group1', 'group2'],
userReads: [
{userId: 1, readAt: 'date1'},
{userId: 2, readAt: 'date2'},
{userId: 3, readAt: 'date3'},
]
}
{
targets: ['group1'],
userReads: [
{userId: 1, readAt: 'date4'}
]
}
DESIRED OUTPUT:
{
groupsNotificationsCount: {
group1: 2,
group2: 1
},
usersNotificationsCount: {
1: 2,
2: 1,
3: 1
}
}
At first I tried this aggregate:
[{
$match: {
targets: {
$in: ['group/1','group/2']
},
}
}, {
$project: {
targets: 1,
userReads: 1
}
}, {
$unwind: {
path: '$targets'
}
}, {
$match: {
targets: {
$in: ['group/1','group/2']
}
}
}, {
$group: {
_id: '$targets',
countForGroup: {
$count: {}
},
userReads: {
$push: '$userReads'
}
}
}, {
$addFields: {
userReads: {
$reduce: {
input: '$userReads',
initialValue: [],
'in': {
$concatArrays: [
'$$value',
'$$this'
]
}
}
}
}
}]
I have the right counts for each group in my documents like so:
{
_id: 'group1',
countForGroup: 2,
userReads: [
{userId: 1, readAt: 'date1'},
{userId: 2, readAt: 'date2'},
{userId: 3, readAt: 'date3'},
{userId: 1, readAt: 'date4'},
]
}
But now I have no idea how to go on from there to get my desired output
CodePudding user response:
This is a perfect use case for using $facet
. You can process groupsNotificationsCount
and usersNotificationsCount
separately by $unwind
and $group
the count. Afterwards by wrangling into array of k-v tuples, you can construct your expected form by using $arrayToObject
db.collection.aggregate([
{
"$facet": {
"groupsNotificationsCount": [
{
"$unwind": "$targets"
},
{
$group: {
_id: "$targets",
count: {
$sum: 1
}
}
}
],
"usersNotificationsCount": [
{
"$unwind": "$userReads"
},
{
$group: {
_id: "$userReads.userId",
count: {
$sum: 1
}
}
}
]
}
},
{
"$project": {
groupsNotificationsCount: {
"$arrayToObject": {
"$map": {
"input": "$groupsNotificationsCount",
"as": "g",
"in": {
k: "$$g._id",
v: "$$g.count"
}
}
}
},
usersNotificationsCount: {
"$arrayToObject": {
"$map": {
"input": "$usersNotificationsCount",
"as": "u",
"in": {
k: {
$toString: "$$u._id"
},
v: "$$u.count"
}
}
}
}
}
}
])
Here is the Mongo playground for your reference.