如何修改嵌套在另一个数组中的数组中的MongoDB对象?

huangapple go评论70阅读模式
英文:

How to Modify MongoDB Object Located in an Array that is Nested in Another Array?

问题

以下是翻译的部分:

我遇到一个问题,我需要修改位于数组中的特定对象的特定字段,但我需要在另一个数组中过滤出该对象。例如,假设我有以下文档:

{
 _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'
      }
     ]
   }
 ]
}

我想要做以下操作:
1)从“builds”数组中过滤出特定的“build”对象。
2)从“artifacts”数组中过滤出特定的“artifact”对象。
3)将“minioPath”字段更新为所需的值。

对于这个问题,我正在使用NestJS中的MongoDB来构建聚合管道。以下是我目前的代码:

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;
  }

到目前为止,我能够过滤出特定的“build”对象,但我不确定如何继续过滤出特定的“artifact”对象。聚合管道变得有点混乱,所以任何建议将不胜感激!

英文:

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: &#39;1&#39;
 name: &#39;Plan&#39;,
 builds: [
   {
     _id: &#39;11&#39;
     number: 20,
     type: &#39;Test Object 1&#39;,
     artifacts: [
      {
        link: &#39;helloworld.com&#39;,
        minioPath: &#39;test.zip&#39;
        _id: &#39;111&#39;

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

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: &#39;$artifacts&#39;,
                as: &#39;artifact&#39;,
                cond: {
                  $eq: [
                    &#39;$$artifact._id&#39;,
                    new Types.ObjectId(&#39;111&#39;),
                  ],
                },
              },
            },
          },
        },
      },
    ];

    const {
      builds: [result],
    } = await this.builds
      .aggregate&lt;Partial&lt;Build&gt;&gt;([matchStage, ...filterBuildStage])
      .then(([doc]) =&gt; {
        if (_.isUndefined(doc) || _.isEmpty(doc?.builds)) {
          throw new ApiError(HttpStatus.NOT_FOUND, &#39;No data found&#39;);
        }
        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!

答案1

得分: 0

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

英文:

filtering out the specific artifact object

to filter out of them

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

MONGO-PLAYGROUND

here how to update

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

MONGO-PLAYGROUND

答案2

得分: 0

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.

英文:

The update is pretty easy using &quot;arrayFilters&quot;.

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

Try it on [mongoplayground.net](https://mongoplayground.net/p/UWuEwjmns8L "Click me!").

huangapple
  • 本文由 发表于 2023年3月4日 04:37:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/75631670.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定