2012-05-20 24 views
18

Xét một cấu trúc tài liệu Mongo đơn giản:MongoDB: upserting: chỉ đặt giá trị nếu tài liệu đã được chèn

{_id, firstTime, lastTime}

Các khách hàng cần để chèn một tài liệu với một ID được biết đến, hoặc cập nhật tài liệu hiện có. 'LastTime' sẽ luôn được đặt thành thời gian mới nhất. Đối với 'firstTime', nếu tài liệu đang được chèn, thì 'firstTime' sẽ được đặt thành thời gian hiện tại. Tuy nhiên, nếu tài liệu đã được tạo, thì 'firstTime' vẫn không thay đổi. Tôi muốn làm điều đó hoàn toàn với những thăng trầm (để tránh nhìn lên).

Tôi đã thu thập thông tin http://www.mongodb.org/display/DOCS/Updating, nhưng tôi không thấy cách hoạt động cụ thể đó có thể được thực hiện.

Tôi không tin rằng đây là điều gì đó không hợp lý, có các hoạt động $ push và $ addToSet thực hiện điều đó một cách hiệu quả trên các trường mảng, không có gì giống như trên các trường đơn giản. Nó giống như có nên có một cái gì đó như hoạt động $ setIf.

+0

* nếu tài liệu đã được tạo, trường sẽ vẫn không thay đổi * không được gọi là upsert (như trong tiêu đề của bạn) –

+0

@ om-nom-nom Tôi đã phác thảo trường hợp đơn giản nhất, tôi đã cập nhật mô tả, do đó, có một trường luôn được cập nhật. –

+1

Có vẻ như tính năng này được nhắm mục tiêu cho 2,4: https://jira.mongodb.org/browse/SERVER-340 – JohnnyHK

Trả lời

27

tôi chạy vào cùng một vấn đề chính xác và không có giải pháp đơn giản cho tuy nhiên < 2.4 từ 2.4 $ setOnInsert điều hành hãy để bạn làm chính xác điều đó.

db.collection.update(<query>, 
         { $setOnInsert: { "firstTime": <TIMESTAMP> } }, 
         { upsert: true } 
        ) 

Xem 2.4 release notes of setOnInsert để biết thêm thông tin.

1

Không có cách nào để thực hiện việc này chỉ với một lần truy cập. Bạn sẽ phải làm điều đó như là 2 hoạt động - trước tiên hãy thử chèn tài liệu, nếu nó đã tồn tại, chèn sẽ thất bại do vi phạm khóa trùng lặp trên chỉ mục _id. Sau đó, bạn thực hiện thao tác cập nhật để đặt lastTime cho đến bây giờ.

+0

IMHO, điều này sẽ đánh bại mục đích, đang thực hiện và chờ đợi, số tiền hoạt động đầu tiên cần tra cứu đồng bộ. Tôi không thấy sự khác biệt trong "cố gắng thất bại" và tìm và cập nhật ... –

+1

Có một điều kiện chủng tộc với phương pháp tìm và cập nhật và cập nhật với nhiều nhà văn đồng thời. Nếu một nhà văn khác đi vào và tạo/thay đổi tài liệu giữa khi chuỗi đầu tiên đã đọc và khi nào nó viết, bạn có thể cuộn lên ghi đè luồng mà luồng kia đã làm. – stbrody

+0

Đó là lý do tại sao tôi muốn nó trong một hoạt động write() duy nhất, do đó, để yêu cầu Mongo thực hiện nó một cách nguyên tử. –

1

Tôi chạy vào một vấn đề rất giống nhau khi cố gắng upsert tài liệu dựa trên nội dung đang tồn tại - có lẽ giải pháp này sẽ làm việc cho bạn cũng:

Hãy thử loại bỏ các thuộc tính _id ra khỏi hồ sơ của bạn và chỉ sử dụng nó trong các truy vấn phần cập nhật của bạn (bạn sẽ phải dịch từ pymongo nói ...)

myid = doc.get('_id') 
del doc['_id'] 
mycollection.update({'_id':myid}, {'$set':doc}, upsert=True) 
Các vấn đề liên quan