2012-04-24 25 views
105

Với tài liệu này được lưu trong MongoDBLàm thế nào để một phần cập nhật một đối tượng trong MongoDB nên đối tượng mới sẽ che phủ/sáp nhập với hiện tại một

{ 
    _id : ..., 
    some_key: { 
     param1 : "val1", 
     param2 : "val2", 
     param3 : "val3" 
    } 
} 

Một đối tượng với thông tin mới về param2param3 từ thế giới bên ngoài cần phải được lưu

var new_info = { 
    param2 : "val2_new", 
    param3 : "val3_new" 
}; 

tôi muốn kết hợp/che phủ các lĩnh vực mới trong trạng thái hiện tại của đối tượng để param1 mà không nhận được gỡ bỏ

Làm điều này

db.collection.update( { _id:...} , { $set: { some_key : new_info } } 

Sẽ dẫn đến MongoDB thực hiện chính xác như được hỏi và đặt some_key thành giá trị đó. thay thế cái cũ.

{ 
    _id : ..., 
    some_key: { 
     param2 : "val2_new", 
     param3 : "val3_new" 
    } 
} 

Cách để MongoDB cập nhật chỉ các trường mới (không nêu rõ từng trường một)? để có được điều này:

{ 
    _id : ..., 
    some_key: { 
     param1 : "val1", 
     param2 : "val2_new", 
     param3 : "val3_new" 
    } 
} 

Tôi đang sử dụng client Java, nhưng bất kỳ ví dụ sẽ được đánh giá cao

+0

hãy bỏ phiếu cho việc hợp nhất vấn đề $: https://jira.mongodb.org/browse/SERVER- 21094 – Ali

Trả lời

71

Nếu tôi hiểu câu hỏi một cách chính xác, bạn muốn cập nhật một tài liệu với những nội dung của tài liệu khác, nhưng chỉ các trường không có sẵn và hoàn toàn bỏ qua các trường đã được đặt (ngay cả khi có giá trị khác).

Không có cách nào để thực hiện điều đó trong một lệnh.

Trước tiên, bạn phải truy vấn tài liệu, tìm ra những gì bạn muốn $set và sau đó cập nhật nó (sử dụng các giá trị cũ làm bộ lọc phù hợp để đảm bảo bạn không nhận được bản cập nhật đồng thời).


Đọc khác câu hỏi của bạn là bạn hài lòng với $set, nhưng không muốn đặt rõ ràng tất cả các trường. Làm thế nào bạn sẽ vượt qua trong dữ liệu sau đó?

Bạn biết bạn có thể làm như sau:

db.collection.update( { _id:...} , { $set: someObjectWithNewData } 
+2

Nếu bạn muốn đặt rõ ràng tất cả các trường ... – morgs32

+0

Nếu bạn muốn đặt tất cả các trường một cách vô điều kiện, bạn có thể sử dụng [$ multi] (https://docs.mongodb.com/manual/reference/method/ db.collection.cập nhật/# đa tham số) tham số, như thế này: 'db.collection.update ({_id: ...}, {$ thiết lập: someObjectWithNewData, {$ đa: true}}) ' –

+5

Không có $ đa tham số. Có một tùy chọn đa (đó là những gì bạn liên kết đến), nhưng điều đó không ảnh hưởng đến cách các trường được cập nhật. Nó kiểm soát việc bạn cập nhật một tài liệu hay tất cả các tài liệu phù hợp với tham số truy vấn. –

7

Mongo phép bạn cập nhật các văn bản lồng nhau sử dụng một quy ước .. Hãy xem: Updating nested documents in mongodb. Dưới đây là một câu hỏi khác trong quá khứ về cập nhật hợp nhất, giống như câu hỏi bạn đang tìm kiếm Tôi tin: MongoDB atomic update via 'merge' document

+1

Điều này là tốt để biết, nhưng không phải câu hỏi của tôi :) –

1

Có vẻ như bạn có thể đặt isPartialObject có thể thực hiện những gì bạn muốn.

+0

đã thử nó. nó không cho phép bạn tiết kiệm một phần đối tượng nếu tôi không nhầm ... nhưng cảm ơn –

69

Tôi đã giải quyết nó bằng chức năng của riêng mình. Nếu bạn muốn cập nhật trường được chỉ định trong tài liệu bạn cần giải quyết rõ ràng.

Ví dụ:

{ 
    _id : ..., 
    some_key: { 
     param1 : "val1", 
     param2 : "val2", 
     param3 : "val3" 
    } 
} 

Nếu bạn muốn cập nhật param2 chỉ, đó là sai lầm khi làm:

db.collection.update( { _id:...} , { $set: { some_key : new_info } } //WRONG 

Bạn phải sử dụng:

db.collection.update( { _id:...} , { $set: { some_key.param2 : new_info } } 

Vì vậy, tôi đã viết một chức năng giống như vậy:

function _update($id, $data, $options=array()){ 

    $temp = array(); 
    foreach($data as $key => $value) 
    { 
     $temp["some_key.".$key] = $value; 
    } 

    $collection->update(
     array('_id' => $id), 
     array('$set' => $temp) 
    ); 

} 

_update('1', array('param2' => 'some data')); 
+7

Đây phải là câu trả lời được chấp nhận. Để có hàm flattenObject tốt hơn, hãy xem https://gist.github.com/penguinboy/762197 – steph643

+0

Cảm ơn phản hồi của bạn đã giúp hướng dẫn tôi. Tôi đã được sửa đổi giá trị của một khóa cụ thể của người dùng trong bộ sưu tập người dùng như sau: 'db.users.update ({_id: ObjectId (" 594dbc3186bb5c84442949b1 ")}, {$ set: {resume: {url:" http://i.imgur.com/UFX0yXs.jpg "}}})' –

8

Bạn có thể sử dụng dấu chấm để truy nhập và đặt trường sâu bên trong đối tượng, mà không ảnh hưởng đến các thuộc tính khác của các đối tượng đó.

Với đối tượng bạn đã nêu ở trên:

> db.test.insert({"id": "test_object", "some_key": {"param1": "val1", "param2": "val2", "param3": "val3"}}) 
WriteResult({ "nInserted" : 1 }) 

Chúng tôi có thể cập nhật chỉ some_key.param2some_key.param3:

> db.test.findAndModify({ 
... query: {"id": "test_object"}, 
... update: {"$set": {"some_key.param2": "val2_new", "some_key.param3": "val3_new"}}, 
... new: true 
... }) 
{ 
    "_id" : ObjectId("56476e04e5f19d86ece5b81d"), 
    "id" : "test_object", 
    "some_key" : { 
     "param1" : "val1", 
     "param2" : "val2_new", 
     "param3" : "val3_new" 
    } 
} 

Bạn có thể nghiên cứu kỹ sâu như bạn muốn. Điều này cũng hữu ích cho việc thêm các thuộc tính mới vào một đối tượng mà không ảnh hưởng đến các đối tượng hiện có.

1

tôi đã thành công làm việc đó theo cách này:

db.collection.update( { _id:...} , { $set: { 'key.another_key' : new_info } }); 

Tôi có một chức năng để xử lý hồ sơ tôi cập nhật tự động

function update(prop, newVal) { 
    const str = `profile.${prop}`; 
    db.collection.update({ _id:...}, { $set: { [str]: newVal } }); 
} 

Lưu ý: 'hồ sơ' là cụ thể cho việc thực hiện của tôi, nó chỉ là chuỗi của khóa mà bạn muốn sửa đổi.

6

Giải pháp tốt nhất là trích xuất các thuộc tính từ đối tượng và tạo cặp khóa-giá trị ký hiệu chấm phẳng. Bạn có thể sử dụng ví dụ thư viện này:

https://www.npmjs.com/package/mongo-dot-notation

Nó có .flatten chức năng cho phép bạn thay đổi đối tượng vào bộ căn hộ bất động sản có thể được sau đó trao cho $ thiết sửa đổi, mà không lo lắng rằng bất kỳ tài sản của hiện tại của bạn Đối tượng DB sẽ bị xóa/ghi đè mà không cần.

Taken từ mongo-dot-notation tài liệu:

var person = { 
    firstName: 'John', 
    lastName: 'Doe', 
    address: { 
    city: 'NY', 
    street: 'Eighth Avenu', 
    number: 123 
    } 
}; 



var instructions = dot.flatten(person) 
console.log(instructions); 
/* 
{ 
    $set: { 
    'firstName': 'John', 
    'lastName': 'Doe', 
    'address.city': 'NY', 
    'address.street': 'Eighth Avenu', 
    'address.number': 123 
    } 
} 
*/ 

Và sau đó nó tạo chọn hoàn hảo - nó sẽ cập nhật tính CHỈ nhất định. EDIT: Tôi muốn trở thành nhà khảo cổ học một số lần;)

+0

hoạt động như một sự quyến rũ, cảm ơn! – caffeinescript

0

sử dụng $ bộ làm quá trình này

.update({"_id": args.dashboardId, "viewData._id": widgetId}, {$set: {"viewData.$.widgetData": widgetDoc.widgetData}}) 
.exec() 
.then(dashboardDoc => { 
    return { 
     result: dashboardDoc 
    }; 
}); 
Các vấn đề liên quan