2011-12-01 30 views
25

Tôi đã tìm cách tạo một câu lệnh cập nhật sẽ lấy trường số hiện có và sửa đổi nó bằng một biểu thức. Ví dụ: nếu tôi có một trường được gọi là Giá, có thể thực hiện cập nhật đặt Giá thành giảm 50% giá trị hiện tại không?Nhân trường theo giá trị trong Mongodb

Vì vậy, cho { Price : 19.99 }

Tôi muốn làm db.collection.update({tag : "refurb"}, {$set {Price : Price * 0.50 }}, false, true);

này có thể được thực hiện hoặc làm tôi phải đọc giá trị lại cho khách hàng, thay đổi, sau đó cập nhật? Tôi đoán câu hỏi sau đó là biểu thức có thể được sử dụng trong bản cập nhật, và họ có thể tham khảo tài liệu đang được cập nhật hay không.

+3

Xin lưu ý rằng trong một phiên bản sắp tới của Mongo, bạn có thể làm điều này mà không cần tất cả eval này và DB khóa gần như miễn phí . Kiểm tra và có thể chấp nhận câu trả lời mới, để các nhà phát triển mới không sử dụng thông tin lỗi thời. –

Trả lời

34

Bạn có thể chạy mã phía máy chủ với db.eval().

db.eval(function() { 
    db.collection.find({tag : "refurb"}).forEach(function(e) { 
     e.Price = e.Price * 0.5; 
     db.collection.save(e); 
    }); 
}); 

Lưu ý điều này sẽ chặn DB, vì vậy tốt hơn nên làm cặp hoạt động tìm-cập nhật.

Xem http://www.mongodb.org/display/DOCS/Server-side+Code+Execution

+0

Cảm ơn. Bạn đang nói tôi nên sử dụng eval() như bạn đã hiển thị, hoặc nên làm điều đó phía khách hàng với tìm/cập nhật để tránh chặn? – Brad

+1

@Brad bạn nên đánh giá tổng chi phí của hoạt động cập nhật cụ thể này. Nếu hoạt động sẽ dài (nhiều tài liệu trong bộ sưu tập sẽ được cập nhật), bạn không bao giờ nên sử dụng eval. Không có chi phí lớn để truy vấn đầu tiên một tài liệu và sau đó cập nhật nó thay vì cập nhật tại chỗ. Đặc biệt nếu bạn giới hạn các trường được truy vấn cho các tài liệu lớn và sử dụng tính năng chỉ mục được bao phủ (http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-CoveredIndexes) – pingw33n

+1

Thật tuyệt, cảm ơn. Tôi thấy cũng eval() không làm việc với sharding, do đó, quy tắc nó ra cho tôi dù sao dài hạn. Nolock là một bổ sung thú vị. – Brad

-1

Vâng, điều này có thể thực hiện với nguyên tử là $ set.

Bạn có một vài lựa chọn:

  • sử dụng eval() giải pháp bởi pingw33n
  • đề xuất lấy tài liệu mà bạn muốn thay đổi để có được giá trị hiện tại và sửa đổi nó với một bộ
  • nếu bạn có tốc độ hoạt động cao, bạn có thể muốn chắc chắn focument không thay đổi trong khi bạn lấy giá trị của nó (sử dụng giải pháp trước) để bạn có thể muốn sử dụng findAndModify (xem this page để lấy cảm hứng về cách thực hiện).

Điều đó thực sự phụ thuộc vào ngữ cảnh của bạn: với áp lực rất thấp trên db, tôi sẽ tìm giải pháp pingw33n. Với tốc độ hoạt động rất cao, tôi sẽ sử dụng giải pháp thứ ba.

+0

Cảm ơn.Tôi không thấy làm thế nào findAndModify sẽ cho phép sử dụng một biểu hiện mặc dù, đó là mục tiêu chính của tôi. – Brad

+0

@Brad findAndModify không cho phép sử dụng biểu thức nhưng nó cho phép thực hiện hành động hai pha: đầu tiên tìm nạp mục và sau đó cập nhật (với giảm 50%) chỉ khi nó không thay đổi kể từ khi truy xuất – kamaradclimber

19

Trong Mongo 2.6.x mới có $mul operator. Nó sẽ nhân giá trị của trường theo số với cú pháp sau.

{ 
    $mul: { field: <number> } 
} 

Vì vậy, trong trường hợp của bạn, bạn sẽ cần phải làm như sau:

db.collection.update(
    { tag : "refurb"}, 
    { $mul: { Price : 0.5 } } 
); 
+1

Tôi không đủ cao đại diện để bình luận, nếu không điều này sẽ là một bình luận trên bài viết trên bởi Salvador Dali đã giúp tôi nhưng có định dạng sai. Thực tế là: {$ mul: {field: }} Không phải {field: {$ mul: }} – Wake

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