i have an a nested array. preformed aggregation to make the subarray the new root.
Category.aggregate([{$unwind: "$SubCats"}, { $replaceRoot: {newRoot: '$SubCats'}} ])
now i need to find by id.
using this would return empty reuslts:
Category.aggregate([{$unwind: "$SubCats"}, { $replaceRoot: {newRoot: '$SubCats'}}, {$match: {_id: `${req.params.id}`}} ])
using $elemMatch is not supported for my atlas tier. and using findById() gives this erro 'Category.aggregate(...).findById is not a function'
array:
[
{
_id: '61cae5daf5bfbebd7cf748ee'
title: 'category 1',
SubCats: [
{
_id: '61cae5daf5bfbebd7cf748ef'
name: 'subcat 1',
image: '/assets/images/vr-box-6203301_1920.jpg',
},
{
_id: '61cae5daf5bfbebd7cf748fb'
name: 'subcat 2',
image: '/assets/images/galaxy-s20_highlights_kv_00.jpg',
},
]
},
]
after aggregation:
[
{
_id: '61cae5daf5bfbebd7cf748ef'
name: 'subcat 1',
image: '/assets/images/vr-box-6203301_1920.jpg',
},
{
_id: '61cae5daf5bfbebd7cf748fb'
name: 'subcat 2',
image: '/assets/images/galaxy-s20_highlights_kv_00.jpg',
},
]
CodePudding user response:
Why not just move the $match stage to be at the start of the pipeline? it will also improve the pipeline's performance as you won't unwind and replace root on many irrelevant documents:
Category.aggregate([ {$match: {_id: `${req.params.id}`}}, {$unwind: "$SubCats"}, { $replaceRoot: {newRoot: '$SubCats'}} ])
If for some reason you don't want to do this then you have to preserve the original id field throughout the pipeline, specifically through the $replaceRoot stage, like so:
Category.aggregate([
{
$unwind: "$SubCats"
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
'$SubCats',
{ original_id: "$_id" }
]
}
}
},
{
$match: {original_id: `${req.params.id}`}
}
])
CodePudding user response:
Field _id is an ObjectId, thus the query must be like this:
Category.aggregate([
{ $unwind: "$SubCats" },
{ $replaceRoot: {newRoot: '$SubCats'} },
{ $match: {_id: ObjectId(`${req.params.id}`) } }
])
But you simply use
Category.aggregate([
{ $match: {"SubCats._id": ObjectId(`${req.params.id}`) } }
])
or use $filter
Category.aggregate([
{
$set: {
SubCats: {
$filter: {
input: "$SubCats",
cond: { $eq: ["$$this._id", ObjectId(`${req.params.id}`)] }
}
}
}
}
])
CodePudding user response:
so i needed to install mongodb from npm i didnt have it installed intially because i was conncting to a cloud mongodb databasse.
so
npm i mongodb
then import
import mongodb from 'mongodb'
const {ObjectId} = mongodb
and then this is what worked:
Category.aggregate([{$unwind: "$SubCats"}, { $replaceRoot: {newRoot: '$SubCats'}}, {$match: {_id: ObjectId(req.params.id)} } ])
