MongoDB: $set specific fields for a document array elements only if not null

MongoDB: $set specific fields for a document array elements only if not null

我有一个 collection 包含以下文件(例如):

{
  "_id": {
    "$oid": "61acefe999e03b9324czzzzz"
  },
  "matchId": {
    "$oid": "61a392cc54e3752cc71zzzzz"
  },
  "logs": [
    {
      "actionType": "CREATE",
      "data": {
        "talent": {
          "talentId": "qq",
          "talentVersion": "2.10",
          "firstName": "Joelle",
          "lastName": "Doe",
          "socialLinks": [
            {
              "type": "FACEBOOK",
              "url": "https://www.facebook.com"
            },
            {
              "type": "LINKEDIN",
              "url": "https://www.linkedin.com"
            }
          ],
          "webResults": [
            {
              "type": "VIDEO",
              "date": "2021-11-28T14:31:40.728Z",
              "link": "http://placeimg.com/640/480",
              "title": "Et necessitatibus",
              "platform": "Repellendus"
            }
          ]
        },
        "createdBy": "DEVELOPER"
      }
    },
    {
      "actionType": "UPDATE",
      "data": {
        "talent": {
          "firstName": "Joelle new",
          "webResults": [
            {
              "type": "VIDEO",
              "date": "2021-11-28T14:31:40.728Z",
              "link": "http://placeimg.com/640/480",
              "title": "Et necessitatibus",
              "platform": "Repellendus"
            }
          ]
        }
      }
    }
  ]
},
{
  "_id": {
    "$oid": "61acefe999e03b9324caaaaa"
  },
  "matchId": {
    "$oid": "61a392cc54e3752cc71zzzzz"
  },
  "logs": [....]
}

一个简单的细分:我在collection中有很多objects像这样的。它们是一种审计日志,用于对其他文档采取的操作,'Match(es)'。例如 CREATE + 数据,UPDATE + 数据等

如您所见,文档的 logs 字段是一个 objects 的数组,每个都描述了这些操作中的一个。 data 对于每个操作 可能包含也可能不包含 特定字段,这反过来也可以是 objects 的数组:socialLinkswebResults.

我正在尝试从 所有 这些具有指定匹配 ID 的文档中删除敏感数据。 对于每个文档,我想遍历 logs 数组字段,并更改特定字段的值 只有当它们存在时 ,例如:将 firstName 更改为*****,与 lastName 相同,如果出现的话。另外,遍历 socialLinks 数组(如果存在),对于其中的每个元素,如果字段 url 存在,也将其更改为 *****

到目前为止,我已尝试对此查询进行许多细微的修改:

      $set: {
        'logs.$[].data.talent.socialLinks.$[].url': '*****',
        'logs.$[].data.talent.webResults.$[].link': '*****',
        'logs.$[].data.talent.webResults.$[].title': '*****',
        'logs.$[].data.talent.firstName': '*****',
        'logs.$[].data.talent.lastName': '*****',
      },

还有一些人使用这种聚合查询:

[{
      $set: {
        'talent.socialLinks.$[el].url': {
          $cond: [{ $ne: ['el.url', null] },'*****', undefined],
        },
      },
    }]

导致如下错误: message: "The path 'logs.0.data.talent.socialLinks' must exist in the document in order to apply array updates.",

但我无法让它工作...:(

希望得到有关如何准确实现这种 set-only-if-exists 行为的解释。 一个工作示例也将不胜感激,谢谢。

建议使用 $\[<indentifier>\] (filtered positional operator) and arrayFilters 更新数组字段中的嵌套文档。

arrayFilters中,用$exists检查是否存在符合条件的文档并进行更新。

db.collection.update({},
{
  $set: {
    "logs.$[a].data.talent.socialLinks.$[].url": "*****",
    "logs.$[b].data.talent.webResults.$[].link": "*****",
    "logs.$[b].data.talent.webResults.$[].title": "*****",
    "logs.$[c].data.talent.firstName": "*****",
    "logs.$[d].data.talent.lastName": "*****",
    
  }
},
{
  arrayFilters: [
    {
      "a.data.talent.socialLinks": {
        $exists: true
      }
    },
    {
      "b.data.talent.webResults": {
        $exists: true
      }
    },
    {
      "c.data.talent.firstName": {
        $exists: true
      }
    },
    {
      "d.data.talent.lastName": {
        $exists: true
      }
    }
  ]
})

Sample Mongo Playground