我需要替换某些文档中的字符串。我用谷歌搜索了这段代码,但遗憾的是它没有改变任何东西。我不确定下面这行的语法:
pulpdb = db.getSisterDB("pulp_database");
var cursor = pulpdb.repos.find();
while (cursor.hasNext()) {
var x = cursor.next();
x['source']['url'].replace('aaa', 'bbb'); // is this correct?
db.foo.update({_id : x._id}, x);
}
我想添加一些调试打印以查看值是什么,但我没有使用MongoDB Shell的经验。我只需要替换它:
{ "source": { "url": "http://aaa/xxx/yyy" } }
与
{ "source": { "url": "http://bbb/xxx/yyy" } }
答案 0 :(得分:37)
它通常不会更正:如果您有字符串http://aaa/xxx/aaa
(yyy
等于aaa
),您最终会得到http://bbb/xxx/bbb
。
但如果你对此感到满意,那么代码就可以了。
使用print
功能添加调试信息:
var cursor = db.test.find();
while (cursor.hasNext()) {
var x = cursor.next();
print("Before: "+x['source']['url']);
x['source']['url'] = x['source']['url'].replace('aaa', 'bbb');
print("After: "+x['source']['url']);
db.test.update({_id : x._id}, x);
}
(顺便说一下,如果你想打印出对象,还有printjson
函数)
答案 1 :(得分:1)
MongoDB可以通过mapreduce进行字符串搜索/替换。是的,您需要有一个非常特殊的数据结构 - 您无法在顶部键中包含任何内容,但您需要将所有内容存储在value
下的子文档下。像这样:
{
"_id" : ObjectId("549dafb0a0d0ca4ed723e37f"),
"value" : {
"title" : "Top 'access denied' errors",
"parent" : "system.admin_reports",
"p" : "\u0001\u001a%"
}
}
一旦你整齐地设置了这个,你就可以做到:
$map = new \MongoCode("function () {
this.value['p'] = this.value['p'].replace('$from', '$to');
emit(this._id, this.value);
}");
$collection = $this->mongoCollection();
// This won't be called.
$reduce = new \MongoCode("function () { }");
$collection_name = $collection->getName();
$collection->db->command([
'mapreduce' => $collection_name,
'map' => $map,
'reduce' => $reduce,
'out' => ['merge' => $collection_name],
'query' => $query,
'sort' => ['_id' => 1],
]);
答案 2 :(得分:1)
如果您使用的是MongoDB 2.6或更高版本,最好的方法是使用.forEach
方法循环游标对象,并使用"bulk"操作更新每个文档以获得最高效率。
var bulk = db.collection.initializeOrderedBulkOp();
var count = 0;
db.collection.find().forEach(function(doc) {
print("Before: "+doc.source.url);
bulk.find({ '_id': doc._id }).update({
'$set': { 'source.url': doc.source.url.replace('aaa', 'bbb') }
})
count++;
if(count % 200 === 0) {
bulk.execute();
bulk = db.collection.initializeOrderedBulkOp();
}
// Clean up queues
if (count > 0)
bulk.execute();
来自MongoDB 3.2的Bulk() API及其关联的methods已弃用,您需要使用db.collection.bulkWrite()
方法。
您需要循环遍历游标,动态构建查询并将$push
每个操作添加到数组中。
var operations = [];
db.collection.find().forEach(function(doc) {
print("Before: "+doc.source.url);
var operation = {
updateOne: {
filter: { '_id': doc._id },
update: {
'$set': { 'source.url': doc.source.url.replace('aaa', 'bbb') }
}
}
};
operations.push(operation);
})
operations.push({
ordered: true,
writeConcern: { w: "majority", wtimeout: 5000 }
})
db.collection.bulkWrite(operations);
答案 3 :(得分:1)
现在,
Mongo 4.2
,db.collection.updateMany
(db.collection.update
的别名)可以接受聚合管道,最终允许根据其自身值更新字段。Mongo 4.4
开始,新的聚合运算符$replaceOne
使替换字符串的一部分变得非常容易。// { "source" : { "url" : "http://aaa/xxx/yyy" } }
// { "source" : { "url" : "http://eee/xxx/yyy" } }
db.collection.updateMany(
{ "source.url": { $regex: /aaa/ } },
[{
$set: { "source.url": {
$replaceOne: { input: "$source.url", find: "aaa", replacement: "bbb" }
}}
}]
)
// { "source" : { "url" : "http://bbb/xxx/yyy" } }
// { "source" : { "url" : "http://eee/xxx/yyy" } }
{ "source.url": { $regex: /aaa/ } }
)是匹配查询,用于过滤要更新的文档(包含"aaa"
的文档)$set: { "source.url": {...
)是更新聚合管道(请注意方括号表示使用聚合管道):
$set
是新的聚合运算符(Mongo 4.2
),在这种情况下,它将替换字段的值。$replaceOne
运算符来计算新值。请注意,如何根据source.url
自身的值($source.url
)直接对其进行修改。请注意,这是服务器端完全处理的操作,不允许您执行问题的调试打印部分。