skip to Main Content

I have the problem where I need to modify a specific field of a object that is located in a array, but I would need to filter out the object within another array to get that specific object. For example, lets say I have the following document:

{
 _id: '1'
 name: 'Plan',
 builds: [
   {
     _id: '11'
     number: 20,
     type: 'Test Object 1',
     artifacts: [
      {
        link: 'helloworld.com',
        minioPath: 'test.zip'
        _id: '111'

      },
      {
        link: 'helloworld.com',
        minioPath: 'test15.zip',
        _id: '112'
      }
     ]
   },
   {
     _id: '12'
     number: 21,
     type: 'Test Object 2',
     artifacts: [
      {
        link: 'mongo.com',
        minioPath: 'test20.zip',
        _id: '211'
      },
      {
        link: 'mongo.com',
        minioPath: 'test25.zip',
        _id: '212'
      }
     ]
   }
 ]
}

What I would like to do is the following:

  1. Filter out the specific build object from the builds array.
  2. Filter out the specific artifact object from the artifacts array.
  3. Update the minioPath field to desired value.

For this problem, I am using MongoDB in NestJS to build an aggregation pipeline. This is what I have so far:

async getBuildItemArtifacts(id: string, buildItemId: string) {
    const buildPlanCondition = isMongoId(id)
      ? { _id: new Types.ObjectId(id) }
      : { key: id };

    const matchStage: PipelineStage.Match = { $match: buildPlanCondition };
    const filterBuildStage: PipelineStage[] = [
      {
        $project: {
          builds: {
            artifacts: {
              $filter: {
                input: '$artifacts',
                as: 'artifact',
                cond: {
                  $eq: [
                    '$$artifact._id',
                    new Types.ObjectId('111'),
                  ],
                },
              },
            },
          },
        },
      },
    ];

    const {
      builds: [result],
    } = await this.builds
      .aggregate<Partial<Build>>([matchStage, ...filterBuildStage])
      .then(([doc]) => {
        if (_.isUndefined(doc) || _.isEmpty(doc?.builds)) {
          throw new ApiError(HttpStatus.NOT_FOUND, 'No data found');
        }
        return doc;
      });

    return result;
  }

So far, I’m able to filter out the specific build object, but I’m now sure how to go about filtering out the specific artifact object. The aggregation pipeline got a little confusing, so any advice would be much appreciated!

2

Answers


  1. filtering out the specific artifact object

    to filter out of them

    db.collection.aggregate([
      {
        "$match": {
          _id: "64011d1c2839dd1845354dfb"
        }
      },
      {
        $project: {
          "builds": {
            "$filter": {
              "input": {
                "$map": {
                  "input": "$builds",
                  "as": "build",
                  "in": {
                    "_id": "$$build._id",
                    "artifacts": {
                      "$filter": {
                        "input": "$$build.artifacts",
                        "as": "artifact",
                        "cond": {
                          $eq: [
                            "$$artifact._id",
                            "64011d302839dd1845354e00",
                            
                          ]
                        }
                      }
                    }
                  }
                }
              },
              "as": "build",
              "cond": {
                "$ne": [
                  "$$build.artifacts",
                  []
                ]
              }
            }
          },
          
        },
        
      },
      
    ])
    

    MONGO-PLAYGROUND

    here how to update

    db.collection.update({
      "_id": "64011d1c2839dd1845354dfb",
      "builds._id": "64011d302839dd1845354dfe",
    },
    {
      $set: {
        "builds.$.artifacts.$[elem].minioPath": "mini mini"
      },
      
    },
    {
      "arrayFilters": [
        {
          "elem._id": "64011d302839dd1845354e00"
        }
      ]
    })
    

    MONGO-PLAYGROUND

    Login or Signup to reply.
  2. The update is pretty easy using "arrayFilters".

    db.collection.update({
      _id: "1"
    },
    {
      "$set": {
        "builds.$[buildElem].artifacts.$[artElem].minioPath": "test42.zip"
      }
    },
    {
      "arrayFilters": [
        {"buildElem._id": "11"},
        {"artElem._id": "111"}
      ]
    })
    

    Try it on mongoplayground.net.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search