Với MongoDB, sẽ có những trường hợp bạn muốn cập nhật nhiều tài liệu chỉ bằng một thao tác. Bạn có thể lặp qua từng tài liệu và cập nhật thủ công, nhưng updateMany mang lại một giải pháp nhanh và hiệu quả hơn.
Trong hướng dẫn ngắn này, chúng ta sẽ học cách dùng toán tử updateMany trong MongoDB và cách tối ưu truy vấn để đạt hiệu năng tốt nhất có thể.
Để xây dựng nền tảng vững chắc về khả năng xử lý dữ liệu của MongoDB bằng Python, hãy cân nhắc khám phá khóa học Introduction to MongoDB in Python.
Xem ví dụ thực tế về cập nhật nhiều tài liệu MongoDB
Để minh họa, hãy dùng một ví dụ thực tế trong đó bạn có thể muốn cập nhật nhiều hơn một tài liệu cùng lúc.
Lấy dữ liệu sau làm nền tảng cho ví dụ:
[{"name":"Nic Raboy","title":"Master of Shenanigans","salary":50000,"last_raise_date": new Date("2013-06-01") },{"name":"Megan Grant","title":"Word Wrangler","salary":125000,"last_raise_date": new Date("2020-12-01") },{"name":"Tony Kim","title":"Alliance Czar","salary":80000,"last_raise_date": new Date("2025-02-01") },];Được hỗ trợ bởi
Trong JSON trên, chúng ta có ba nhân viên tại một công ty hư cấu. Công ty muốn tăng lương cho mọi người nếu họ chưa nhận được điều chỉnh lương trong một khoảng thời gian nhất định.
Để cập nhật tất cả những người đủ điều kiện, ta có thể dùng toán tử updateMany trong MongoDB. Để hoàn thành nhiệm vụ, ta có thể có câu lệnh như sau:
db.employees.updateMany({"last_raise_date":{"$lte":newDate("2024-01-01")}},{"$mul":{"salary":1.06},"$set":{"last_raise_date":newDate()}});Được hỗ trợ bởi
Vậy thao tác updateMany ở trên làm gì?
Nhìn lại một chút, toán tử updateMany nhận hai tham số chính và một tham số thứ ba tùy chọn.
Tham số thứ nhất là một đối tượng đại diện cho dữ liệu dùng để lọc.
Tham số thứ hai là các thay đổi sẽ áp dụng cho các kết quả tìm được từ bộ lọc.
Tham số thứ ba tùy chọn có thể là { “upsert”: true }, tức là sẽ chèn một tài liệu nếu không có kết quả khớp.
Với điều đó, trước hết ta lọc tất cả tài liệu có last_raise_date sớm hơn "2024-01-01". Nhìn lại bộ dữ liệu rất cơ bản của chúng ta, có hai trong ba tài liệu khớp:
[{"name":"Nic Raboy","title":"Master of Shenanigans","salary":50000,"last_raise_date": new Date("2013-06-01") },{"name":"Megan Grant","title":"Word Wrangler","salary":125000,"last_raise_date": new Date("2020-12-01") }];Được hỗ trợ bởi
Hai thay đổi khác nhau sẽ được áp dụng cho các tài liệu đã lọc dựa trên tham số tiêu chí thay đổi.
Trước tiên, ta dùng toán tử $mul để nhân một trường với một giá trị. Trong ví dụ này, ta muốn tăng lương 6% cho mọi nhân viên đủ điều kiện. Nghĩa là ta chỉ cần nhân giá trị hiện tại của trường với 1.06.
Để giúp ghi nhận việc điều chỉnh lương đồng thời tránh tăng nhầm về sau, ta muốn cập nhật last_raise_date thành ngày hiện tại:
Nếu chạy lại thao tác updateMany, sẽ không có gì xảy ra vì last_raise_date dùng trong bộ lọc sẽ không còn khớp với bất kỳ tài liệu nào trong ba tài liệu của chúng ta.
Trên đây chỉ là một ví dụ; tiêu chí lọc của bạn có thể phức tạp hơn nhiều, và tương tự, những gì bạn định thay đổi cũng có thể phức tạp hơn tùy theo tình huống sử dụng. Bạn có thể tìm hiểu thêm về updateMany của MongoDB trong video này.
Tăng hiệu năng cập nhật với chỉ mục MongoDB
Trong ví dụ, chúng ta làm việc với ba tài liệu nhỏ. Gần như bất kỳ thao tác nào trên bộ sưu tập này cũng đều nhanh vì khối lượng không lớn. Tuy nhiên, hãy nghĩ đến môi trường sản xuất nơi bạn làm việc với hàng triệu tài liệu hoặc thường xuyên chạy thao tác cập nhật.
Nếu dùng toán tử updateMany trên hàng triệu tài liệu, thao tác có thể mất thời gian trừ khi bạn đã thiết lập chỉ mục phù hợp cho tiêu chí lọc.
Để tạo chỉ mục cho ví dụ, ta có thể chạy như sau:
db.employees.createIndex({"last_raise_date":1});Được hỗ trợ bởi
Bạn có thể xác minh rằng thao tác updateMany đang sử dụng chỉ mục bằng cách chạy lệnh sau:
db.runCommand({"explain":{"update":"employees","updates":[{"q":{"last_raise_date":{"$lte":newDate("2024-01-01")}},"u":{"$mul":{"salary":1.06},"$set":{"last_raise_date":newDate()}}}]},"verbosity":"allPlansExecution"});Được hỗ trợ bởi
Trong kết quả, nếu inputStage là "IXSCAN" thì bạn đang dùng chỉ mục và tối đa hóa hiệu năng updateMany. Nếu inputStage là "COLLSCAN" thì bạn chưa dùng chỉ mục và có thể cần xem lại cách tạo chỉ mục dựa trên tiêu chí lọc.
Để tránh nhầm lẫn, ở trên chúng ta dùng runCommand để phân tích thao tác cập nhật nhiều tài liệu. Nếu bạn không cần thông tin profiler, hãy dùng thao tác updateMany đơn giản và gọn gàng hơn.
Kết luận
Cập nhật nhiều tài liệu trong một thao tác duy nhất trong MongoDB không hề khó, như bạn đã thấy trong toàn bộ hướng dẫn.
Với toán tử updateMany, ta có thể định nghĩa tiêu chí lọc để đối chiếu với tài liệu, rồi tiêu chí thay đổi cùng danh sách thay đổi cần áp dụng. Thao tác updateMany có thể tối ưu thêm bằng cách đảm bảo bạn có chỉ mục phù hợp với tiêu chí lọc.
Nếu bạn mới làm quen với cơ sở dữ liệu phi quan hệ, khóa học Introduction to NoSQL sẽ cung cấp cái nhìn tổng quan hữu ích về các khái niệm như kho tài liệu.
Câu hỏi thường gặp
Sự khác biệt giữa updateOne và updateMany trong MongoDB là gì?⌄
updateOne sửa đổi tài liệu khớp đầu tiên, trong khi updateMany cập nhật tất cả tài liệu đáp ứng tiêu chí lọc. Hãy chọn dựa trên phạm vi thay đổi bạn mong muốn.
Có thể dùng updateMany với upsert trong MongoDB không?⌄
Có, thêm { upsert: true } làm đối số thứ ba sẽ chèn tài liệu mới nếu không tìm thấy kết quả khớp. Tuy nhiên, tùy chọn này thường được dùng với updateOne hơn.
Những trường hợp sử dụng phổ biến của updateMany là gì?⌄
Thường dùng cho cập nhật hàng loạt như điều chỉnh giá, thay đổi trạng thái người dùng hoặc làm sạch các trường lỗi thời trong bộ dữ liệu lớn.
updateMany có trả về dữ liệu kết quả nào không?⌄
Có, nó trả về một đối tượng với thông tin như matchedCount và modifiedCount, cho biết có bao nhiêu tài liệu được khớp và cập nhật.
Điều gì xảy ra nếu không có tài liệu nào khớp với bộ lọc trong updateMany?⌄
Nếu không có tài liệu nào khớp và không dùng upsert, thao tác sẽ hoàn tất mà không có thay đổi nào. Không có lỗi được ném ra.
updateMany có nguyên tử trong MongoDB không?⌄
Không, nó không nguyên tử trên nhiều tài liệu. Mỗi cập nhật trên từng tài liệu là nguyên tử, nhưng không phải nguyên tử theo nhóm.
Làm thế nào để kiểm thử hiệu năng của các thao tác updateMany?⌄
Dùng các phương thức explain() hoặc runCommand({ explain: ... }) để xem truy vấn có dùng chỉ mục hay quét toàn bộ bộ sưu tập.
Tôi có thể chuỗi nhiều toán tử cập nhật trong updateMany không?⌄
Có, MongoDB hỗ trợ kết hợp các toán tử như $set, $inc, $mul, v.v. trong một lần gọi updateMany duy nhất.
Chỉ mục ảnh hưởng thế nào đến các thao tác updateMany?⌄
Chỉ mục có thể cải thiện hiệu năng đáng kể bằng cách giảm số tài liệu cần quét trong quá trình lọc.
Làm thế nào để hoàn tác một thao tác updateMany bị nhầm?⌄
Bạn sẽ cần khôi phục từ bản sao lưu hoặc log, vì MongoDB không có tính năng hoàn tác tích hợp cho updateMany. Hãy luôn thử nghiệm trên môi trường staging và sao lưu dữ liệu sản xuất trước.
Tác giả
Nic Raboy
Nic Raboy là Trưởng bộ phận Quan hệ Nhà phát triển tại MongoDB, nơi anh dẫn dắt một đội ngũ các nhà phát triển Python, Java, C# và PHP tạo ra nội dung xuất sắc giúp các nhà phát triển triển khai MongoDB thành công trong dự án của mình. Anh có kinh nghiệm với Golang và JavaScript, và thường xuyên viết về nhiều hành trình phát triển của bản thân.
Với MongoDB, sẽ có những trường hợp bạn muốn cập nhật nhiều tài liệu chỉ bằng một thao tác. Bạn có thể lặp qua từng tài liệu và cập nhật thủ công, nhưng
updateManymang lại một giải pháp nhanh và hiệu quả hơn.Trong hướng dẫn ngắn này, chúng ta sẽ học cách dùng toán tử updateMany trong MongoDB và cách tối ưu truy vấn để đạt hiệu năng tốt nhất có thể.
Để xây dựng nền tảng vững chắc về khả năng xử lý dữ liệu của MongoDB bằng Python, hãy cân nhắc khám phá khóa học Introduction to MongoDB in Python.
Xem ví dụ thực tế về cập nhật nhiều tài liệu MongoDB
Để minh họa, hãy dùng một ví dụ thực tế trong đó bạn có thể muốn cập nhật nhiều hơn một tài liệu cùng lúc.
Lấy dữ liệu sau làm nền tảng cho ví dụ:
Trong JSON trên, chúng ta có ba nhân viên tại một công ty hư cấu. Công ty muốn tăng lương cho mọi người nếu họ chưa nhận được điều chỉnh lương trong một khoảng thời gian nhất định.
Để cập nhật tất cả những người đủ điều kiện, ta có thể dùng toán tử
updateManytrong MongoDB. Để hoàn thành nhiệm vụ, ta có thể có câu lệnh như sau:Vậy thao tác
updateManyở trên làm gì?Nhìn lại một chút, toán tử
updateManynhận hai tham số chính và một tham số thứ ba tùy chọn.{ “upsert”: true }, tức là sẽ chèn một tài liệu nếu không có kết quả khớp.Với điều đó, trước hết ta lọc tất cả tài liệu có
last_raise_datesớm hơn "2024-01-01". Nhìn lại bộ dữ liệu rất cơ bản của chúng ta, có hai trong ba tài liệu khớp:Hai thay đổi khác nhau sẽ được áp dụng cho các tài liệu đã lọc dựa trên tham số tiêu chí thay đổi.
Trước tiên, ta dùng toán tử
$mulđể nhân một trường với một giá trị. Trong ví dụ này, ta muốn tăng lương 6% cho mọi nhân viên đủ điều kiện. Nghĩa là ta chỉ cần nhân giá trị hiện tại của trường với 1.06.Để giúp ghi nhận việc điều chỉnh lương đồng thời tránh tăng nhầm về sau, ta muốn cập nhật
last_raise_datethành ngày hiện tại:Nếu chạy lại thao tác
updateMany, sẽ không có gì xảy ra vìlast_raise_datedùng trong bộ lọc sẽ không còn khớp với bất kỳ tài liệu nào trong ba tài liệu của chúng ta.Trên đây chỉ là một ví dụ; tiêu chí lọc của bạn có thể phức tạp hơn nhiều, và tương tự, những gì bạn định thay đổi cũng có thể phức tạp hơn tùy theo tình huống sử dụng. Bạn có thể tìm hiểu thêm về updateMany của MongoDB trong video này.
Tăng hiệu năng cập nhật với chỉ mục MongoDB
Trong ví dụ, chúng ta làm việc với ba tài liệu nhỏ. Gần như bất kỳ thao tác nào trên bộ sưu tập này cũng đều nhanh vì khối lượng không lớn. Tuy nhiên, hãy nghĩ đến môi trường sản xuất nơi bạn làm việc với hàng triệu tài liệu hoặc thường xuyên chạy thao tác cập nhật.
Nếu dùng toán tử
updateManytrên hàng triệu tài liệu, thao tác có thể mất thời gian trừ khi bạn đã thiết lập chỉ mục phù hợp cho tiêu chí lọc.Để tạo chỉ mục cho ví dụ, ta có thể chạy như sau:
Bạn có thể xác minh rằng thao tác
updateManyđang sử dụng chỉ mục bằng cách chạy lệnh sau:Trong kết quả, nếu
inputStagelà "IXSCAN" thì bạn đang dùng chỉ mục và tối đa hóa hiệu năngupdateMany. NếuinputStagelà "COLLSCAN" thì bạn chưa dùng chỉ mục và có thể cần xem lại cách tạo chỉ mục dựa trên tiêu chí lọc.Để tránh nhầm lẫn, ở trên chúng ta dùng
runCommandđể phân tích thao tác cập nhật nhiều tài liệu. Nếu bạn không cần thông tin profiler, hãy dùng thao tácupdateManyđơn giản và gọn gàng hơn.Kết luận
Cập nhật nhiều tài liệu trong một thao tác duy nhất trong MongoDB không hề khó, như bạn đã thấy trong toàn bộ hướng dẫn.
Với toán tử
updateMany, ta có thể định nghĩa tiêu chí lọc để đối chiếu với tài liệu, rồi tiêu chí thay đổi cùng danh sách thay đổi cần áp dụng. Thao tácupdateManycó thể tối ưu thêm bằng cách đảm bảo bạn có chỉ mục phù hợp với tiêu chí lọc.Nếu bạn mới làm quen với cơ sở dữ liệu phi quan hệ, khóa học Introduction to NoSQL sẽ cung cấp cái nhìn tổng quan hữu ích về các khái niệm như kho tài liệu.