Bạn cần cung cấp nhiều khóa cho $set
với vị trí $
nhà điều hành
để cập nhật cả hai khóa phù hợp.
Tôi thích cách thao tác đối tượng ES6 hiện đại hơn:
let params = { "_id" : "xxxproductid", "name" : "xxx", "img" : "yyy" };
let update = [
{ 'store.products._id': params._id },
{ "$set": Object.keys(params).filter(k => k != '_id')
.reduce((acc,curr) =>
Object.assign(acc,{ [`store.products.$.${curr}`]: params[curr] }),
{ })
}
];
User.update(...update,callback);
Điều này sẽ tạo ra lệnh gọi đến MongoDB dưới dạng (với mongoose.set('debug', true)
) được bật để chúng tôi thấy yêu cầu:
Về cơ bản, bạn lấy params
đầu vào của mình ở đâu và cung cấp _id
làm đối số đầu tiên cho "truy vấn":
{ 'store.products._id': params._id },
Phần còn lại lấy "khóa" từ đối tượng thông qua Object.keys
tạo một "mảng" mà chúng ta có thể "lọc" bằng Array.filter()
và sau đó chuyển đến Array.reduce
để chuyển đổi các khóa đó thành một Object
.
Bên trong .reduce()
chúng tôi gọi là Object.assign()
mà "hợp nhất" các đối tượng với các khóa đã cho, được tạo trong biểu mẫu này:
Object.assign(acc,{ [`store.products.$.${curr}`]: params[curr] }),
Sử dụng cú pháp mẫu để gán khóa "hiện tại" (curr) "" vào tên khóa mới, lại sử dụng Cú pháp gán khóa ES6 []:
cho phép các tên biến trong các ký tự đối tượng.
Đối tượng "đã hợp nhất" kết quả được chuyển trở lại để được gán cho đối tượng "gốc" trong đó $set
được sử dụng cho khóa của bản cập nhật, vì vậy các khóa "được tạo" hiện là con của khóa đó.
Tôi sử dụng một mảng cho các đối số hoàn toàn cho mục đích gỡ lỗi, nhưng sau đó mảng đó cũng cho phép cú pháp rõ ràng hơn trên .update()
thực tế sử dụng "spread" ...
toán tử để gán các đối số:
User.update(...update,callback);
Sạch sẽ và đơn giản, và một số kỹ thuật JavaScript mà bạn nên học để thao tác với đối tượng và mảng. Chủ yếu vì DSL truy vấn MongoDB về cơ bản là "Đối tượng" và "Mảng". Vì vậy, hãy học cách vận dụng chúng.