如何替换Mongo中所有文档中的字符串

时间:2012-04-06 10:48:56

标签: javascript mongodb mongodb-query

我需要替换某些文档中的字符串。我用谷歌搜索了这段代码,但遗憾的是它没有改变任何东西。我不确定下面这行的语法:

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" } }

4 个答案:

答案 0 :(得分:37)

它通常不会更正:如果您有字符串http://aaa/xxx/aaayyy等于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.2Bulk() 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.2db.collection.updateManydb.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)直接对其进行修改。

请注意,这是服务器端完全处理的操作,不允许您执行问题的调试打印部分。