如何替换mongodb文档中的子字符串
Posted
技术标签:
【中文标题】如何替换mongodb文档中的子字符串【英文标题】:How to replace substring in mongodb document 【发布时间】:2012-09-25 19:29:14 【问题描述】:我在表单集合中有很多 mongodb 文档:
....
"URL":"www.abc.com/helloWorldt/..."
.....
我想用helloWorld
替换helloWorldt
得到:
....
"URL":"www.abc.com/helloWorld/..."
.....
如何为我的收藏中的所有文档实现这一点?
【问题讨论】:
【参考方案1】:db.media.find(mediaContainer:"ContainerS3").forEach(function(e,i)
e.url=e.url.replace("//a.n.com","//b.n.com");
db.media.save(e);
);
【讨论】:
你能详细说明一下吗?它是如何工作的代码的含义是什么?也适用于其他用户? 太棒了。我的情况是——我有一个字段是一个数组——所以我不得不添加一个额外的循环。我的查询是: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)); )
@doe "e" 这里表示找到的每个文档的副本。该副本的 url 值(区分大小写,请注意,这与提问者的“url”不同)根据其原始 url 值进行更新。 "e" 将其所有原始字段与一个修改后的字段一起保留。将 e 保存回集合会覆盖原始的“e”。这里不需要“i”,可以从函数声明中删除。
请给其他用户解释一下??
确实可以只更新已更改的一个字段,而不是读取和写回整个文档吗?【参考方案2】:
现在,
从Mongo 4.2
、db.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/
) 是匹配查询,用于过滤要更新的文档(包含 "helloWorldt"
的文档),以便加快查询速度。
第二部分($set: URL: ...
)是更新聚合管道(注意方括号表示使用聚合管道):
$set
是一个新的聚合运算符 (Mongo 4.2
),在这种情况下会替换字段的值。
使用新的$replaceOne
运算符计算新值。请注意URL
是如何根据其自身的值($URL
)直接修改的。
在Mongo 4.4
和开始Mongo 4.2
之前,由于缺少正确的字符串$replace
运算符,我们必须使用$concat
和$split
的普通组合:
db.collection.updateMany(
URL: $regex: "/helloWorldt/" ,
[
$set: URL:
$concat: [
$arrayElemAt: [ $split: [ "$URL", "/helloWorldt/" ] , 0 ] ,
"/helloWorld/",
$arrayElemAt: [ $split: [ "$URL", "/helloWorldt/" ] , 1 ]
]
]
)
【讨论】:
谢谢,它可以与find
中的正则表达式一起使用吗?
谢谢,替换时是否需要斜杠(“/”)?
@dhalfageme 我在后一个例子中看到了混乱。 $regex
运算符(即$regex: "/helloWorldt/"
)后面的正斜杠是正则表达式分隔符,这是必需的。在示例中的其他任何地方,正斜杠都是 URL 路径分隔符,可能不是必需的。只有当 OP 的 URL 的路径包含他们想要保留的 /helloWorldthirsty/ 时,它们才是必需的。【参考方案3】:
目前,您不能使用字段的值来更新它。因此,您必须遍历文档并使用函数更新每个文档。这里有一个示例说明您可以如何做到这一点:MongoDB: Updating documents using data from the same document
【讨论】:
【参考方案4】:要替换文档中 ALL 次出现的子字符串,请使用:
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);
);
【讨论】:
变量不需要在循环中,所以把它们放在前面。 变量应该是常量。【参考方案5】:使用 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.将 .json 文件中的字符串替换为 sed(用于 linux 终端)或任何其他工具
sed -i 's/oldstring/newstring/g' products.json
4.使用带有 --drop 标签的 mongoimport 导入 .json 集合,它将在导入之前删除集合
mongoimport --db=<db_name> --drop --collection products <products.json
或者,您可以在 mongoimport 中使用 --uri 进行连接 和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/
【讨论】:
【参考方案6】:节点。使用mongodb package from npm
db.collection('ABC').find(url: /helloWorldt/).toArray((err, docs) =>
docs.forEach(doc =>
let URL = doc.URL.replace('helloWorldt', 'helloWorld');
db.collection('ABC').updateOne(_id: doc._id, URL);
);
);
【讨论】:
【参考方案7】:我对所选答案(@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));
)
【讨论】:
【参考方案8】:现在你可以做到了!
我们可以使用 Mongo 脚本来动态操作数据。它对我有用!
我使用这个脚本来更正我的地址数据。
当前地址示例:“第五大道 12 号”。
我想删除最后一个多余的逗号,即预期的新地址“No.12, FIFTH AVENUE”。
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);
希望这会有所帮助!
【讨论】:
有什么办法可以替换mongodb中大二进制字符串的部分子字符串?【参考方案9】:这可以通过在方法replace
的第一部分中使用Regex
来完成,它将用第二个字符串替换该字符串的[all if g
in regex pattern] 出现,这与 javascript 中的正则表达式相同,例如:
const string = "www.abc.com/helloWorldt/...";
console.log(string);
var pattern = new RegExp(/helloWorldt/)
replacedString = string.replace(pattern, "helloWorld");
console.log(replacedString);
由于正则表达式正在替换字符串,现在我们可以通过 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/"
>
【讨论】:
【参考方案10】:如果你想搜索一个子字符串,并用另一个替换它,你可以尝试如下,
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);
)
【讨论】:
以上是关于如何替换mongodb文档中的子字符串的主要内容,如果未能解决你的问题,请参考以下文章