There is an items (mongoose) schema that looks like this (simplified to what it matters to the question):
{
brand: {
name: String,
},
title: String,
description: [{ lang: String, text: String }],
shortDescription: [{ lang: String, text: String }],
variants: {
cnt: Number,
attrs: [
{
displayType: String,
displayContent: String,
displayName: [{ lang: String, text: String }],
name: String,
},
],
}
}
I'm trying to filter the items by language, so I've constructed the following query:
db.items.aggregate([
{ $match: { 'description.lang': 'ca', 'shortDescription.lang': 'ca' } },
{ $project: {
'brand.name': 1,
title: 1,
description: {
'$filter': {
input: '$description',
as: 'description',
cond: { $eq: ['$$description.lang', 'ca'] }
}
},
shortDescription: {
'$filter': {
input: '$shortDescription',
as: 'shortDescription',
cond: { $eq: ['$$shortDescription.lang', 'ca'] }
}
},
'variants.cnt': 1,
'variants.attrs': 1
} }
])
And it works as expected: it filters description
and shortDescription
by language. Right now I'm wondering if it could be possible to filter every variants.attrs.$.displayName
as well. Is there any way to do it?
I've been trying to $unwind
variant.attrs
but I get completly lost when trying to $group
again and I'm not really sure if this is the best way...
You are nearly there. Try these steps:
$unwind
stage before $project
stage to expand the outer array of documents, i.e. variants.attrs
variants.attrs.displayName
in the $project
stage.variants
key. $group
stage and group by all the elements except the sub-array. Use $push
to rebuild the sub array in group by stage.Lastly, add $project
stage to rebuild the document to its original structure.
db.items.aggregate([
{ $match: { 'description.lang': 'ca', 'shortDescription.lang': 'ca' } },
{ $unwind : "$variants.attrs" },
{ $project: {
'_id' : 1,
'brand.name': 1,
title: 1,
description: {
'$filter': {
input: '$description',
as: 'description',
cond: { $eq: ['$$description.lang', 'ca'] }
}
},
shortDescription: {
'$filter': {
input: '$shortDescription',
as: 'shortDescription',
cond: { $eq: ['$$shortDescription.lang', 'ca'] }
}
},
'variants.attrs.displayName' : {
'$filter' : {
input: '$variants.attrs.displayName',
as: 'variants_attrs_displayName',
cond: { $eq : ['$$variants_attrs_displayName.lang','ca']}
}
},
'variants.cnt': 1,
'variants.attrs.displayType': 1,
'variants.attrs.displayContent' : 1,
'variants.attrs.name' : 1
}
} , { $group:
{
_id : {
_id: "$_id",
title: "$title",
brand:"$brand",
description:"$description",
shortDescription:"$shortDescription",
variants_cnt : "$variants.cnt"
},
variants_attrs : { $push :
{
displayType : "$variants.attrs.displayType",
displayContent : "$variants.attrs.displayContent",
displayName : "$variants.attrs.displayName",
name: "$variants.attrs.name"
}
}
}
},
{ $project :
{
"_id" : 0,
brand : "$_id.brand",
title : "$_id.title",
description : "$_id.description",
shortDescription : "$_id.shortDescription",
variants : {
cnt : "$_id.variants_cnt" ,
attrs : "$variants_attrs"
}
}
}
])
Depending on your use case, you should reconsider your data model design to avoid duplication of filter values. i.e. 'description.lang': 'ca', 'shortDescription.lang': 'ca', 'variants.attrs.displayName.lang': 'ca'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With