Home > Software design >  mongoDB - find by id after aggregation
mongoDB - find by id after aggregation

Time:01-20

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)} } ])
  •  Tags:  
  • Related