2010-04-09 36 views
23

Tôi có một bộ sưu tập t1 với các lĩnh vực sau đây trong sơ đồ của nóCập nhật trường có giá trị của lĩnh vực khác trong tài liệu

_id, field1, field1 

tôi muốn thiết lập giá trị field1field2 's như sql:

update t1 set field1=field2; 

thế nào thế nào để tôi làm điều đó trong MongoDB?

+1

câu hỏi Rất tương tự: http://stackoverflow.com/questions/3974985/update-mongodb-field-using-value-of-another-field/ –

Trả lời

36

Tin tốt và xấu ở đây.

Tin xấu là AFAIK bạn không thể thực hiện với một lệnh update() duy nhất - mongo không hỗ trợ tham chiếu đến đối tượng hiện tại đang cập nhật.

Tin vui là có nhiều cách khác để làm điều đó, ví dụ: bạn có thể chạy một vòng lặp foreach:

db.item.find(conditions...).forEach(function (doc) { 
    doc.field1 = doc.field2; 
    db.item.save(doc); 
}); 

Bạn có thể chạy foreach trong vỏ admin ('Mongo' lệnh), hoặc thông qua một số phương pháp của lái xe cụ thể của bạn (ví dụ như trong PHP tôi mong đợi nó để làm việc với mongodb.execute() như mô tả ở đây: http://www.php.net/manual/en/mongodb.execute.php)

+13

Bởi vì một lời kêu gọi tiết kiệm() đang được thực hiện trong vòng vòng lặp forEach, con trỏ sẽ bị rối tung lên và hàm này sẽ được gọi nhiều lần cho mỗi tài liệu. Giải pháp là gọi snapshot() trước khi foreach: db.item.find (blah) .snapshot(). ForEach() –

+0

Cảm ơn vì điều đó. Tôi đã không nhận thức được yêu cầu snapshot() cho điều này để làm việc như dự định. TBH Ban đầu tôi thấy ngạc nhiên rằng một chức năng gọi là "forEach" không bảo đảm tên của nó là gì (vì nó tương tự như những gì bạn có thể tìm thấy trong thư viện sưu tập bằng ngôn ngữ lập trình), nhưng sau đó, tôi hiểu rằng có thể có nhiều lý do để làm điều đó. –

+3

Không có cách nào nguyên tử để làm điều này? Giải pháp này không có vẻ rất mạnh mẽ. – UpTheCreek

2

này có thể được thực hiện thông qua:

db.nameOfCollection.find().forEach(
    function (elem) { 
     db.nameOfCollection.update(
      { 
       _id: elem._id 
      }, 
      { 
       $set: { 
        field2: elem.field1 
       } 
      } 
     ); 
    } 
); 
+2

Bạn đã thất bại trong việc sao chép-dán http://stackoverflow.com/a/14423151/2054072 –

8

Bắt đầu từ phiên bản 3.4, chúng ta có thể sử dụng toán tử đường ống $addFields hợp này mà không xử lý phía khách hàng mà là hiệu quả nhất đường.

db.collection.aggregate(
    [ 
     { "$addFields": { "field2": "$field1" }}, 
     { "$out": "collection" } 
    ] 
) 

Trước khi phiên bản 3.4 chúng ta cần phải lặp đối tượng Cursor và sử dụng $set hành thêm lĩnh vực mới với giá trị "field1" hiện có. Bạn cần phải làm điều này bằng cách sử dụng "số lượng lớn" hoạt động cho hiệu quả tối đa.

MongoDB 3.2 không dùng Bulk()associated methods, do đó từ 3,2 trở lên bạn cần sử dụng phương pháp bulkWrite.

var requests = []; 
db.collection.find({}, { 'field1': 1 }).snapshot().forEach(document => { 
    requests.push({ 
     'updateOne': { 
      'filter': { '_id': document._id }, 
      'update': { '$set': { 'field2': document.field1 } } 
     } 
    }); 
    if (requests.length === 1000) { 
     //Execute per 1000 operations and re-init 
     db.collection.bulkWrite(requests); 
     requests = []; 
    } 
}); 

if(requests.length > 0) { 
    db.collection.bulkWrite(requests); 
} 

Từ phiên bản 2,6-3,0 bạn có thể sử dụng Bulk API.

var bulk = db.collection.initializeUnorderedBulOp(); 
var count = 0; 

db.collection.find({}, { 'field1': 1 }).snapshot().forEach(function(document) { 
    bulk.find({ '_id': document._id }).updateOne({ 
     '$set': { 'field2': document.field1 } 
    }); 
    count++; 
    if(count%1000 === 0) { 
     // Excecute per 1000 operations and re-init 
     bulk.execute(); 
     bulk = db.collection.initializeUnorderedBulkOp(); 
    } 
}) 

// clean up queues 
if(count > 0) { 
    bulk.execute(); 
} 
+0

Trong các thử nghiệm của mình, tôi thấy phương pháp tổng hợp được MUCH nhanh hơn. Dữ liệu mẫu của tôi có tài liệu 150K mất 5 giây để định hình lại, trong khi các phương pháp .foreach mất ~ 1,5 phút. Điều gì là caveats/gotchas để được xem xét khi đi với cách tiếp cận tập hợp? – Tung

Các vấn đề liên quan