2012-04-06 79 views
23

我需要替換某些文檔中的字符串。我使用了這個代碼,但不幸的是它並沒有改變任何東西。我不知道就行了波紋管的語法:如何替換Mongo中所有文檔中的字符串

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的外殼沒有經驗。我只需要更換此:

{ "source": { "url": "http://aaa/xxx/yyy" } } 

{ "source": { "url": "http://bbb/xxx/yyy" } } 
+0

Mongo shell運行任意的javascript,這表明你的代碼有效。你只是嘗試過嗎? – Derick 2012-04-06 10:56:22

回答

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功能)

+0

哦,我沒有嘗試「打印」:-)這很簡單!好吧,我可以看到數據進入,我想我有一個在正則表達式中的障礙(真正的案例不是xxx,但https://abc.blablab.com) – lzap 2012-04-06 11:06:49

+0

明白了 - 我必須做x ['source '] ['url'] = x ['source'] ['url']。replace(...)。 – lzap 2012-04-06 11:10:56

+0

嗯由於一些奇怪的原因變量被替換,但數據不存儲然後。我需要執行一個提交還是什麼?我仍然在那裏看到舊數據。 – lzap 2012-04-06 11:13:22

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], 
]); 
+0

這不是一個正確的方法 - mapReduce可以產生一個新的結果集,它不應該被用來「替換「現有的價值這種方式。另外,你依賴於一些非常具體的東西 - 以這種方式來格式化你的集合,只是爲了輸出_id,值對看起來比已經給出的答案更復雜,通過迭代shell中的文檔來完成。 – 2014-12-26 23:20:33

+0

並非所有的Web應用程序都有執行shell命令的權限。另一種方法是將全部檢索到PHP中,替換並保存,但在服務器中肯定會更快。最後,你可以引用一些官方文件,爲什麼它不應該用這種方式?我沒有讀過任何說你不應該合併到源代碼中的內容。 – chx 2014-12-27 05:24:26

+0

你既不映射也不減少:)基本上,你是覆蓋,這不是真正的「mapReduce」的目的 - 你實際上是在更新每個文檔。最好的情況是,這可以被描述爲一種黑客(只適用於文檔的這種確切的特定格式) – 2014-12-29 16:35:10

1

如果您對MongoDB的2.6或更新的版本來做到這一點,最好的方法使用的循環通過遊標對象方法和更新每個文件使用"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()方法。

您需要循環遍歷遊標,動態構建查詢並將每個操作動態構建到數組中。

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); 
相關問題