【问题标题】:How to bulk replace substring in mongoDB array field with keyword?如何用关键字批量替换mongoDB数组字段中的子字符串?
【发布时间】:2020-07-11 07:32:20
【问题描述】:
{
    "_id": ObjectId("5f08e58ae1f788a8beb30519"),
    "__v": NumberInt("0"),
    "dimensions": {
        "height": NumberInt("720"),
        "width": NumberInt("1080")
    },
    "likes": NumberInt("164"),
    "src": [
        "http://mmbiz.qpic.cn/mmbiz_jpg/VZYVS8SibfiaibUE9qr4M2nGG50icSCuiaGFfUrBufC7T3R48ehjSrVSQ7JbfkgFybzjLs4tNMXhX7YmuWicPe2NUiaKQ/0",
        "http://mmbiz.qpic.cn/mmbiz_jpg/VZYVS8SibfiaibUE9qr4M2nGG50icSCuiaGFfkopmyeak2h1oGPkiaHcgcg4DX5swbBHRg6TWibl2ocvpgIaAng0koWMQ/0",
        "http://mmbiz.qpic.cn/mmbiz_jpg/VZYVS8SibfiaibUE9qr4M2nGG50icSCuiaGFfkxTnwtOurQQkajmtlQzIokIM0Ms6qyYh2FCWaCnZqmxOAyEYZyUgdA/0",
        "http://mmbiz.qpic.cn/mmbiz_jpg/VZYVS8SibfiaibUE9qr4M2nGG50icSCuiaGFflamticYWfNkheTMtzcz3wSGib01EsurUA3Royy1A1P0W8muEicMcbbegw/0",
        "http://mmbiz.qpic.cn/mmbiz_jpg/VZYVS8SibfiaibUE9qr4M2nGG50icSCuiaGFfRc3IBJE1amD5BPoELdYjoIvkQ2iaHiaUu0HexWD8niaAJq6fTFIqDgibOA/0"
    ],
    "recommended": true
}

假设我在 mongoDB 中的集合“发现”中有上述数据结构,我想将 src 中的 http:// 替换为 https://,如下所示:

{
    "_id": ObjectId("5f08e58ae1f788a8beb30519"),
    "__v": NumberInt("0"),
    "dimensions": {
        "height": NumberInt("720"),
        "width": NumberInt("1080")
    },
    "likes": NumberInt("164"),
    "src": [
        "https://mmbiz.qpic.cn/mmbiz_jpg/VZYVS8SibfiaibUE9qr4M2nGG50icSCuiaGFfUrBufC7T3R48ehjSrVSQ7JbfkgFybzjLs4tNMXhX7YmuWicPe2NUiaKQ/0",
        "https://mmbiz.qpic.cn/mmbiz_jpg/VZYVS8SibfiaibUE9qr4M2nGG50icSCuiaGFfkopmyeak2h1oGPkiaHcgcg4DX5swbBHRg6TWibl2ocvpgIaAng0koWMQ/0",
        "https://mmbiz.qpic.cn/mmbiz_jpg/VZYVS8SibfiaibUE9qr4M2nGG50icSCuiaGFfkxTnwtOurQQkajmtlQzIokIM0Ms6qyYh2FCWaCnZqmxOAyEYZyUgdA/0",
        "https://mmbiz.qpic.cn/mmbiz_jpg/VZYVS8SibfiaibUE9qr4M2nGG50icSCuiaGFflamticYWfNkheTMtzcz3wSGib01EsurUA3Royy1A1P0W8muEicMcbbegw/0",
        "https://mmbiz.qpic.cn/mmbiz_jpg/VZYVS8SibfiaibUE9qr4M2nGG50icSCuiaGFfRc3IBJE1amD5BPoELdYjoIvkQ2iaHiaUu0HexWD8niaAJq6fTFIqDgibOA/0"
    ],
    "recommended": true
}

有没有我可以做到这一点,而无需遍历每条记录,然后一一更新? (我有数百万条记录,这需要大量时间,而且似乎效率低下......)

我试过了:

db.getCollection("discoveries").updateMany(
  { src: { $exists: true } },
  [{
    $set: { src: {
      $replaceOne: { input: "src.$[]", find: "http://", replacement: "https://" }
    }}
  }]
)

返回:

[Error] Error: collection.updateOne requires update operator

【问题讨论】:

  • 我认为这正是您要寻找的:stackoverflow.com/a/56556298/8296184
  • @VirgilioGM 这个解决方案有点问题, src 是一个数组而不是一个字符串,所以 $replaceOne 似乎没有这样做......
  • 我现在没有电脑可以试用,抱歉,但我认为使用 'src.$[]' 作为要更新的字段会起作用
  • @VirgilioGM thx,请参阅我更新的问题。它返回:collection.updateOne requires update operator

标签: mongodb


【解决方案1】:

此解决方案更多(询问具体而不是通用 IMO)假设 src 中的所有字符串最初以 http 开头,并且需要替换为 https

从 MongoDB 4.2 开始,您可以将聚合管道用于 更新操作。

想法: 是使用使用$map 的聚合管道,其中src 中的所有url 在第4 个索引处拆分,并使用$concat 和@ 与https 连接987654323@。并使用$set 更新src 属性。

db.collection.updateMany({ src: { $exists: true } }, [
  {
    $set: {
      src: {
        $map: {
          input: "$src",
          as: "u",
          in: {
            $concat: [
              "https",
              {
                $substr: ["$$u", 4, -1],
              },
            ],
          },
        },
      },
    },
  },
]);

注意: $split 也可以用来调整这个,而不是 $substr


编辑/更新:基于 cmets,某些 url 可能已经以 https 开头。

db.collection.updateMany({ src: { $exists: true } }, [
  {
    $set: {
      src: {
        $map: {
          input: "$src",
          as: "u",
          in: {
            $cond: {
              if: {
                $eq: [
                  {
                    $size: {
                      $split: ["$$u", "http:"],
                    },
                  },
                  2,
                ],
              },
              then: {
                $concat: [
                  "https:",
                  {
                    $arrayElemAt: [
                      {
                        $split: ["$$u", "http:"],
                      },
                      1,
                    ],
                  },
                ],
              },
              else: "$$u",
            },
          },
        },
      },
    },
  },
]);

【讨论】:

  • an assumption that all strings in src originally starts with http and are needed to replaced with https...实际情况并非如此
  • @AeroWang Ermm.. 纯粹根据问题中的示例进行此查询。所以你说src 中的一些网址可能已经以https 开头?
  • 你说 src 中的一些 url 可能已经以 https 开头 - 是的
  • @AeroWang 更新了回复!结果证明该解决方案不是最佳的,但可以工作。我没有 mongo 4.4 来测试 $replaceOne 这在这里可以很好地工作。希望有人发布更好的解决方案。你可能想看看Another way,如果有大量数据,我会选择它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-08
  • 1970-01-01
  • 2018-07-14
  • 2014-02-05
  • 2014-10-07
相关资源
最近更新 更多