Here I’m adding the Mongo playground URL how my schema structure look like
Now I want 3 unique array elements which are mostPurchased, latestRewards and suggestedRewards.
So I’m trying to achieve by using $facet
{
$facet: {
mostPurchased: [
{
$sort: {
buyerCount: -1
}
},
{
$limit: 15
},
{
$group: {
_id: "$_id",
doc: {
$first: "$$ROOT"
}
}
},
{
$replaceRoot: {
newRoot: "$doc"
}
}
],
latestRewards: [
{
$sort: {
created: -1
}
},
{
$group: {
_id: "$_id",
doc: {
$first: "$$ROOT"
}
}
},
{
$replaceRoot: {
newRoot: "$doc"
}
},
{
$limit: 15
}
],
suggestedRewards: [
{
$match: {
points: {
$lt: 300
}
}
},
{
$group: {
_id: "$_id",
doc: {
$first: "$$ROOT"
}
}
},
{
$replaceRoot: {
newRoot: "$doc"
}
},
{
$limit: 15
}
]
}
},
{
$project: {
mostPurchased: 1,
latestRewards: 1,
suggestedRewards: 1
}
}
But this one producing the duplicate element on each array.
Note: All the stage aggregations should be perform before the projection so that it each array would contain 15 elements. for reference I added 8 elements on mongo playground.
Let me know where I’m going wrong
2
Answers
Use
$group
to aggregate unique documents based on a unique identifier.Apply the
$facet
stage to perform the required operations for each array.There is not enough data in your sample dataset to illustrate top 15 for each groups, so this example uses top 2 to illustrate.
The idea is to assign to each group only once. Here, we assume the priority would be:
So if a document matched all groups, it would be assigned to
mostPurchased
group. If a document matched only group 2 and 3, it would be assigned to group 2. This behaviour is configurable and will be explained in later code.The aggregation pipeline would be like below:
$project
and other stages$setWindowFields
to computemostPurchasedRank
with$rank
$setWindowFields
to computelatestRewardsRank
with$rank
$set
a fieldgrouping
with$switch
. Here is the part where we configure the priority. Based on the calculated rankings in step 2 and 3, we assign documents into different groups.$setWindowFields
to computeinGroupRanking
with$rank
. This helps to avoid we are having too many documents in a group(thus breaching MongoDB 16MB document size limit in later stage)$match
to selectinGroupRanking <= 2
(i.e. document number per group, would be 15 in your original case)7.(optional)
$group
bygrouping
to push all docs inside.Mongo Playground