2012-04-06 9 views
23

Ich muss eine Zeichenfolge in bestimmten Dokumenten ersetzen. Ich habe diesen Code gegooglet, aber er ändert leider nichts. Ich bin über die Syntax auf der Linie unten nicht sicher:So ersetzen Sie die Zeichenfolge in allen Dokumenten in 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); 
} 

Ich möchte einige Debug-Drucke hinzufügen, um zu sehen, was der Wert ist, aber ich habe keine Erfahrungen mit MongoDB Shell. Ich brauche nur diese ersetzen:

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

mit

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

Die Mongo Shell läuft willkürliche Javascript, die darauf hindeutet, dass Ihr Code funktioniert. Hast du es einfach probiert? – Derick

Antwort

37

Es korrigieren Regel nicht: Wenn Sie Zeichenfolge haben http://aaa/xxx/aaa (yyy gleich zu aaa) Sie mit http://bbb/xxx/bbb am Ende werden. Aber wenn Sie damit einverstanden sind, wird der Code funktionieren.

Um Debug-Informationen print Funktion hinzufügen:

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); 
} 

(Und übrigens, wenn Sie Objekte auch printjson Funktion drucken möchten out ist)

+0

Oh ich habe es nicht "print" versucht :-) So einfach! Okay, ich kann sehen, dass die Daten kommen, ich denke, ich habe einen Haken in der Regexp (der wirkliche Fall ist nicht xxx aber https://abc.blablab.com) – lzap

+0

Bekam ich - ich musste x ['Quelle '] [' url '] = x [' source '] [' url ']. ersetzen Sie stattdessen (...). – lzap

+0

Hmm aus irgendeinem seltsamen Grund wird die Variable ersetzt, aber die Daten werden dann nicht gespeichert. Muss ich einen Commit oder etwas durchführen? Ich sehe immer noch alte Daten dort. – lzap

1

MongoDB String-Suche tun/ersetzen über mapreduce. Ja, Sie müssen eine sehr spezielle Datenstruktur dafür haben - Sie können nichts in den Topschlüsseln haben, aber Sie müssen alles unter einem Filialdokument unter value speichern. Wie folgt aus:

{ 
    "_id" : ObjectId("549dafb0a0d0ca4ed723e37f"), 
    "value" : { 
      "title" : "Top 'access denied' errors", 
      "parent" : "system.admin_reports", 
      "p" : "\u0001\u001a%" 
    } 
} 

Sobald Sie diese ordentlich einrichten können Sie tun:

$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

Dies ist kein korrekter Ansatz für das Problem - mapReduce kann eine neue Ergebnismenge erzeugen, sollte nicht verwendet werden, "ersetzen" "bestehende Werte auf diese Weise. Außerdem sind Sie auf etwas extrem Spezifisches angewiesen - Ihre Sammlung auf diese Weise zu formatieren, nur um _id auszugeben, scheint Wertpaaren viel komplizierter zu sein als die bereits gegebene Antwort, um es zu tun, indem Sie über Dokumente in der Shell iterieren. –

+0

Nicht alle Webanwendungen verfügen über Berechtigungen zum Ausführen von Shell-Befehlen. Ein anderer Ansatz wäre es, alles in PHP abzurufen, zu ersetzen und zu speichern, aber im Server ist es sicherlich schneller. Könnten Sie schließlich eine offizielle Dokumentation als Grund angeben, warum sie nicht so verwendet werden sollte? Ich habe nichts gelesen, dass du nicht mit der Quelle verschmelzen solltest. – chx

+0

Sie sind weder Mapping noch Reduzieren :) Grundsätzlich überschreiben Sie und das ist nicht wirklich der Zweck von "mapReduce" - Sie tun buchstäblich ein Update jedes Dokuments. Im besten Fall kann dies als ein Hack beschrieben werden (der nur an genau diesem spezifischen Format des Dokuments funktioniert) –

1

Der beste Weg, dies zu tun, wenn Sie auf MongoDB 2.6 oder neuer sind über den Cursor-Objekt Looping die Verwendung von .forEach Methode und aktualisieren Sie jedes Dokument usin "bulk" Operationen für maximale Effizienz.

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(); 

Von MongoDB 3.2 die Bulk() API und der damit verbundenen methods sind veraltet Sie die db.collection.bulkWrite() Methode verwenden müssen.

Sie benötigen Schleife über den Cursor, bauen Sie Ihre Abfrage dynamisch und $push jede Operation zu einem Array.

Verwandte Themen