如何替换mongodb文档中的子字符串


77

我在表单的集合中有很多mongodb文档:

{
....
"URL":"www.abc.com/helloWorldt/..."
.....
}

我想,以取代helloWorldthelloWorld来获得:

{
....
"URL":"www.abc.com/helloWorld/..."
.....
}

如何为我的收藏集中的所有文档实现这一目标?

Answers:


131
db.media.find({mediaContainer:"ContainerS3"}).forEach(function(e,i) {
    e.url=e.url.replace("//a.n.com","//b.n.com");
    db.media.save(e);
});

2
你能详细说明一下吗?它是如何工作的,代码的含义是什么?对于其他用户呢?
阿曼

3
太棒了 我的情况是-我有一个数组的字段-所以我不得不添加一个额外的循环。我的查询是:db.getCollection("profile").find({"photos": {$ne: "" }}).forEach(function(e,i) { e.photos.forEach(function(url, j) { url = url.replace("http://a.com", "https://dev.a.com"); e.photos[j] = url; }); db.getCollection("profile").save(e); eval(printjson(e)); })
Himel Nag Rana

3
@doe“ e”表示找到的每个文档的副本。该副本具有其url值(区分大小写,请注意,这与问问者的“ url”不同)是根据其url的原始值更新的。“ e”将所有原始字段保留为一个修改后的字段。将e保存回集合中会覆盖原始的“ e”。这里不需要“ i”,可以将其从函数声明中删除。
JMess

请也为其他用户解释??
Pirai Sudie

当然可以只更新一个已更改的字段,而不用读写整个文档吗?
亚瑟·塔卡

31

如今,

  • 开始Mongo 4.2db.collection.updateMany(别名db.collection.update)可以接受的聚合管道,终于使基于自身值的字段的更新。
  • 开始时Mongo 4.4,新的聚合运算符$replaceOne使替换字符串的一部分变得非常容易。
// { URL: "www.abc.com/helloWorldt/..." }
// { URL: "www.abc.com/HelloWo/..." }
db.collection.updateMany(
  { URL: { $regex: /helloWorldt/ } },
  [{
    $set: { URL: {
      $replaceOne: { input: "$URL", find: "helloWorldt", replacement: "helloWorld" }
    }}
  }]
)
// { URL: "www.abc.com/helloWorld/..." }
// { URL: "www.abc.com/HelloWo/..." }
  • 第一部分({ URL: { $regex: /helloWorldt/ } })是match查询,用于过滤要更新的文档(包含的文档"helloWorldt"),并且该文档可以使查询更快。
  • 第二部分($set: { URL: {...)是更新聚合管道(请注意方括号表示使用聚合管道):
    • $set是一个新的聚合运算符(Mongo 4.2),在这种情况下将替换字段的值。
    • 新值是使用new$replaceOne运算符计算的。请注意如何URL根据其自身的值($URL)直接进行修改。

Mongo 4.4和开始Mongo 4.2,由于缺乏适当的字符串的$replace操作,我们必须使用的bancal混合$concat$split

db.collection.updateMany(
  { URL: { $regex: "/helloWorldt/" } },
  [{
    $set: { URL: {
      $concat: [
        { $arrayElemAt: [ { $split: [ "$URL", "/helloWorldt/" ] }, 0 ] },
        "/helloWorld/",
        { $arrayElemAt: [ { $split: [ "$URL", "/helloWorldt/" ] }, 1 ] }
      ]
    }}
  }]
)

谢谢,它可以与regex一起使用find吗?
dimid

谢谢,替换中是否需要斜杠(“ /”)?
dhalfageme

@dhalfageme在后面的示例中,我感到困惑。$regex运算符后面的正斜杠(即$regex: "/helloWorldt/")是必需的正则表达式分隔符。在示例中的其他任何地方,正斜杠都是URL路径定界符,可能没有必要。仅当OP具有要保留的包含/ helloWorldthirsty /的URL时,才需要使用它们。
David Siegal



5

要替换文档中所有出现的子字符串,请使用:

db.media.find({mediaContainer:"ContainerS3"}).forEach(function(e,i) {
var find = "//a.n.com";
var re = new RegExp(find, 'g');
e.url=e.url.replace(re,"//b.n.com");
db.media.save(e);
});

3
var不需要进入循环,因此请将它们放在前面。
保罗

var应该是const。
Mirko

4

我对所选答案(@Naveed的答案)的评论格式已被打乱-因此将其添加为答案。所有功劳归功于Naveed。

-------------------------------------------------- --------------------

太棒了 我的情况是-我有一个数组的字段-所以我不得不添加一个额外的循环。

我的查询是:

db.getCollection("profile").find({"photos": {$ne: "" }}).forEach(function(e,i) {
    e.photos.forEach(function(url, j) {
        url = url.replace("http://a.com", "https://dev.a.com");
        e.photos[j] = url;
    });
    db.getCollection("profile").save(e);
    eval(printjson(e));
})

4

使用mongodump,bsondump和mongoimport。

有时,mongodb集合在嵌套数组/对象等方面变得有点复杂,而在它们周围构建循环会相对困难。我的工作还很原始,但是不管集合的复杂性如何,它都能在大多数情况下工作。

1.使用mongodump将集合导出到.bson

mongodump --db=<db_name> --collection=<products> --out=data/

2.使用bsondump将.bson转换为.json格式

bsondump --outFile products.json data/<db_name>/products.bson

3.用sed(对于Linux终端)或任何其他工具替换.json文件中的字符串。

sed -i 's/oldstring/newstring/g' products.json

4.使用带有--drop标签的mongoimport导入.json集合,在导入之前它将删除该集合

mongoimport --db=<db_name>  --drop --collection products <products.json

或者,您可以使用--uri在mongoimport和mongodump中进行连接

mongodump --uri "mongodb://mongoadmin:mystrongpassword@10.148.0.7:27017,10.148.0.8:27017,10.148.0.9:27017/my-dbs?replicaSet=rs0&authSource=admin" --collection=products --out=data/

1

现在您可以做到!

我们可以使用Mongo脚本即时处理数据。这个对我有用!

我使用此脚本来更正我的地址数据。

当前地址示例:“第五大街12号”。

我要删除最后一个多余的逗号,即预期的新地址“ FIFTH AVENUE 12号”。

var cursor = db.myCollection.find().limit(100);

while (cursor.hasNext()) {
  var currentDocument = cursor.next();

  var address = currentDocument['address'];
  var lastPosition = address.length - 1;

  var lastChar = address.charAt(lastPosition);

  if (lastChar == ",") {

    var newAddress = address.slice(0, lastPosition);


    currentDocument['address'] = newAddress;

    db.localbizs.update({_id: currentDocument._id}, currentDocument);

  }
}

希望这可以帮助!


1

这可以通过Regex在方法的第一部分中使用来完成replace,它将g用第二个字符串替换该字符串的[如果在regex模式中所有]出现,则这与Javascript中的regex相同,例如:

const string = "www.abc.com/helloWorldt/...";
console.log(string);
var pattern = new RegExp(/helloWorldt/)
replacedString = string.replace(pattern, "helloWorld");
console.log(replacedString);

由于regex替换了字符串,现在我们可以通过MongoDB shell轻松地做到这一点,方法是使用该方法查找并迭代每个元素,forEach并在forEach循环内逐个保存,如下所示:

> db.media.find()
{ "_id" : ObjectId("5e016628a16075c5bd26fbe3"), "URL" : "www.abc.com/helloWorld/" }
{ "_id" : ObjectId("5e016701a16075c5bd26fbe4"), "URL" : "www.abc.com/helloWorldt/" }
> 
> db.media.find().forEach(function(o) {o.URL = o.URL.replace(/helloWorldt/, "helloWorld"); printjson(o);db.media.save(o)})
{
    "_id" : ObjectId("5e016628a16075c5bd26fbe3"),
    "URL" : "www.abc.com/helloWorld/"
}
{
    "_id" : ObjectId("5e016701a16075c5bd26fbe4"),
    "URL" : "www.abc.com/helloWorld/"
}
> db.media.find()
{ "_id" : ObjectId("5e016628a16075c5bd26fbe3"), "URL" : "www.abc.com/helloWorld/" }
{ "_id" : ObjectId("5e016701a16075c5bd26fbe4"), "URL" : "www.abc.com/helloWorld/" }
>


0

如果您要搜索子字符串,然后将其替换为另一个字符串,则可以尝试以下操作,

    db.collection.find({ "fieldName": /.*stringToBeReplaced.*/ }).forEach(function(e, i){
        if (e.fieldName.indexOf('stringToBeReplaced') > -1) {
          e.content = e.content.replace('stringToBeReplaced', 'newString');
          db.collection.update({ "_id": e._id }, { '$set': { 'fieldName': e.fieldName} }, false, true);
        }
    }) 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.