2012-04-06 43 views
23

Tôi cần phải thay thế một chuỗi trong các tài liệu nhất định. Tôi đã googled mã này, nhưng nó không may thay đổi bất cứ điều gì. Tôi không chắc chắn về cú pháp trên dòng dưới đây:Làm thế nào để thay thế chuỗi trong tất cả các tài liệu trong 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); 
} 

Tôi muốn thêm một số bản in gỡ lỗi để xem giá trị là gì, nhưng tôi không có kinh nghiệm với MongoDB Shell. Tôi chỉ cần phải thay thế này:

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

với

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

Vỏ Mongo chạy javascript tùy ý cho thấy mã bạn đang hoạt động. Bạn đã thử nó chưa? – Derick

Trả lời

37

Nó không sửa thường: nếu bạn có chuỗi http://aaa/xxx/aaa (yyy tương đương với aaa), bạn sẽ kết thúc với http://bbb/xxx/bbb. Nhưng nếu bạn đồng ý với điều này, mã sẽ hoạt động.

Để thêm thông tin gỡ lỗi sử dụng print chức năng:

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

(Và bằng cách này, nếu bạn muốn in ra đối tượng, đó cũng là printjson chức năng)

+0

Ồ tôi không thử "in" :-) Thật đơn giản! Được rồi, tôi có thể thấy dữ liệu đang đến, tôi đoán tôi có một snag trong regexp (trường hợp thực sự không phải là xxx nhưng https://abc.blablab.com) – lzap

+0

OK - Tôi phải làm x ['source '] [' url '] = x [' nguồn '] [' url ']. thay thế (...) để thay thế. – lzap

+0

Hmm vì một số lý do kỳ lạ biến được thay thế nhưng dữ liệu không được lưu trữ sau đó. Tôi có cần phải thực hiện một cam kết hay một cái gì đó? Tôi vẫn thấy dữ liệu cũ ở đó. – lzap

1

MongoDB có thể làm tìm kiếm chuỗi/thay thế qua mapreduce. Có, bạn cần phải có một cấu trúc dữ liệu rất đặc biệt cho nó - bạn không thể có bất cứ điều gì trong các phím trên cùng nhưng bạn cần phải lưu trữ tất cả mọi thứ dưới một subdocument dưới value. Như thế này:

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

Một khi bạn đã này gọn gàng thiết lập bạn có thể làm:

$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

Đây không phải là một cách tiếp cận chính xác cho vấn đề - mapReduce có thể tạo ra một tập kết quả mới, nó không nên được sử dụng để "thay thế "giá trị hiện tại theo cách này. Ngoài ra, bạn còn phụ thuộc vào thứ gì đó cực kỳ cụ thể - định dạng bộ sưu tập của bạn theo cách này chỉ để xuất _id, các cặp giá trị có vẻ phức tạp hơn câu trả lời đã cho để làm điều đó bằng cách lặp qua các tài liệu trong trình bao. –

+0

Không phải tất cả các ứng dụng web đều có quyền thực hiện các lệnh shell. Một cách tiếp cận khác là lấy tất cả vào PHP, thay thế và lưu lại nhưng trong máy chủ chắc chắn là nhanh hơn. Cuối cùng, bạn có thể trích dẫn một số tài liệu chính thức vì sao nó không nên được sử dụng theo cách này? Tôi đã không đọc bất cứ điều gì nói rằng bạn không nên nhập vào nguồn. – chx

+0

bạn không phải là bản đồ cũng không giảm :) Về cơ bản, bạn đang ghi đè và đó không thực sự là mục đích của "mapReduce" - nghĩa là bạn đang thực hiện cập nhật từng tài liệu. Tốt nhất, điều này có thể được mô tả như là một hack (chỉ hoạt động trên định dạng cụ thể chính xác của tài liệu này) –

1

Cách tốt nhất để làm điều này nếu bạn đang ở trên MongoDB 2.6 hoặc phiên bản mới hơn được Looping trên đối tượng con trỏ bằng cách sử dụng .forEach phương pháp và cập nhật từng tài liệu usin "bulk" hoạt động để đạt hiệu quả tối đa.

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

Từ MongoDB 3.2 các Bulk() API và nó liên quan đến methods đang bị phản đối, bạn sẽ cần phải sử dụng các phương pháp db.collection.bulkWrite().

Bạn sẽ cần lặp qua con trỏ, tạo truy vấn động và $push mỗi hoạt động vào một mảng.

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); 
Các vấn đề liên quan