Vì vậy, arrayFilters
tùy chọn với $[<identifier>]
được lọc theo vị trí thực sự hoạt động bình thường với loạt bản phát hành phát triển kể từ MongoDB 3.5.12 và cả trong các ứng cử viên phát hành hiện tại cho loạt MongoDB 3.6, nơi điều này thực sự sẽ được phát hành chính thức. Tất nhiên, vấn đề duy nhất là các "trình điều khiển" được sử dụng vẫn chưa thực sự bắt kịp điều này.
Lặp lại cùng một nội dung mà tôi đã đặt khi Cập nhật Mảng lồng nhau với MongoDB:
LƯU Ý Hơi trớ trêu, vì điều này được chỉ định trong đối số "tùy chọn" cho
.update()
và giống như các phương pháp, cú pháp nói chung tương thích với tất cả các phiên bản trình điều khiển phát hành gần đây.Tuy nhiên, điều này không đúng với
mongo
shell, vì cách phương thức được triển khai ở đó ("trớ trêu thay cho khả năng tương thích ngược")arrayFilters
đối số không được công nhận và bị xóa bởi một phương thức nội bộ phân tích cú pháp các tùy chọn để cung cấp "khả năng tương thích ngược" với các phiên bản máy chủ MongoDB trước đó và "kế thừa".update()
Cú pháp gọi API.Vì vậy, nếu bạn muốn sử dụng lệnh trong
mongo
shell hoặc các sản phẩm "dựa trên shell" khác (đặc biệt là Robo 3T), bạn cần có phiên bản mới nhất từ nhánh phát triển hoặc bản phát hành sản xuất kể từ 3.6 trở lên.
Tất cả điều này có nghĩa là việc triển khai "trình điều khiển" hiện tại của .update()
thực sự "loại bỏ" các đối số cần thiết với định nghĩa của arrayFilters
. Đối với NodeJS, điều này sẽ được giải quyết trong loạt phát hành 3.x của trình điều khiển và tất nhiên "mongoose" sau đó có thể sẽ mất một thời gian sau bản phát hành đó để thực hiện các phụ thuộc của chính nó vào trình điều khiển được cập nhật, sau đó sẽ không còn "dải" những hành động như vậy.
Tuy nhiên, bạn vẫn có thể chạy điều này trên được hỗ trợ phiên bản máy chủ, bằng cách quay lại cách sử dụng cú pháp "lệnh cập nhật" cơ bản, vì điều này đã bỏ qua phương thức trình điều khiển được triển khai:
const mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = mongoose.Types.ObjectId;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const uri = 'mongodb://localhost/test',
options = { useMongoClient: true };
const contactSchema = new Schema({
data: String,
type: String,
priority: String,
retries: String
});
const personSchema = new Schema({
name: String,
level: String,
priority: String,
enabled: Boolean,
contacts: [contactSchema]
});
const groupSchema = new Schema({
name: String,
people: [personSchema],
workingHours: { start: String, end: String },
workingDays: { type: [Number], default: undefined },
contactTypes: {
workingHours: { type: [String], default: undefined },
contactTypes: { type: [String], default: undefined }
}
});
const Group = mongoose.model('Group', groupSchema);
function log(data) {
console.log(JSON.stringify(data, undefined, 2))
}
(async function() {
try {
const conn = await mongoose.connect(uri,options);
// Clean data
await Promise.all(
Object.entries(conn.models).map(([k,m]) => m.remove() )
);
// Create sample
await Group.create({
name: "support",
people: [
{
"_id": ObjectId("5a05a8c3e0ce3444f8ec5bd8"),
"enabled": true,
"level": "1",
"name": "Someone",
"contacts": [
{
"type": "email",
"data": "[email protected]"
},
{
"_id": ObjectId("5a05a8dee0ce3444f8ec5bda"),
"retries": "1",
"priority": "1",
"type": "email",
"data": "[email protected]"
}
]
}
]
});
let result = await conn.db.command({
"update": Group.collection.name,
"updates": [
{
"q": {},
"u": { "$set": { "people.$[i].contacts.$[j].data": "new data" } },
"multi": true,
"arrayFilters": [
{ "i._id": ObjectId("5a05a8c3e0ce3444f8ec5bd8") },
{ "j._id": ObjectId("5a05a8dee0ce3444f8ec5bda") }
]
}
]
});
log(result);
let group = await Group.findOne();
log(group);
} catch(e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})()
Vì điều đó sẽ gửi "lệnh" trực tiếp đến máy chủ, chúng tôi thấy bản cập nhật dự kiến trên thực tế đã diễn ra:
Mongoose: groups.remove({}, {})
Mongoose: groups.insert({ name: 'support', _id: ObjectId("5a06557fb568aa0ad793c5e4"), people: [ { _id: ObjectId("5a05a8c3e0ce3444f8ec5bd8"), enabled: true, level: '1', name: 'Someone', contacts: [ { type: 'email', data: '[email protected]', _id: ObjectId("5a06557fb568aa0ad793c5e5") }, { _id: ObjectId("5a05a8dee0ce3444f8ec5bda"), retries: '1', priority: '1', type: 'email', data: '[email protected]' } ] } ], __v: 0 })
{ n: 1,
nModified: 1,
opTime:
{ ts: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
t: 24 },
electionId: 7fffffff0000000000000018,
ok: 1,
operationTime: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
'$clusterTime':
{ clusterTime: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
signature: { hash: [Object], keyId: 0 } } }
Mongoose: groups.findOne({}, { fields: {} })
{
"_id": "5a06557fb568aa0ad793c5e4",
"name": "support",
"__v": 0,
"people": [
{
"_id": "5a05a8c3e0ce3444f8ec5bd8",
"enabled": true,
"level": "1",
"name": "Someone",
"contacts": [
{
"type": "email",
"data": "[email protected]",
"_id": "5a06557fb568aa0ad793c5e5"
},
{
"_id": "5a05a8dee0ce3444f8ec5bda",
"retries": "1",
"priority": "1",
"type": "email",
"data": "new data" // <-- updated here
}
]
}
]
}
Vì vậy, ngay "bây giờ" các trình điều khiển có sẵn "ngoài giá sách" không thực sự triển khai .update()
hoặc đó là các đối tác triển khai khác theo cách tương thích với việc thực sự chuyển qua arrayFilters
cần thiết lý lẽ. Vì vậy, nếu bạn đang "chơi với" một chuỗi phát triển hoặc phát hành máy chủ candiate, thì bạn thực sự nên chuẩn bị sẵn sàng để làm việc với các trình điều khiển "đang chảy máu" và chưa được phát hành.
Nhưng bạn thực sự có thể làm điều này như đã trình bày trong bất kỳ trình điều khiển nào, ở dạng chính xác mà lệnh được đưa ra sẽ không bị thay đổi.
Kể từ khi viết vào ngày 11 tháng 11 năm 2017, không có "chính thức" phát hành MongoDB hoặc các trình điều khiển được hỗ trợ thực sự triển khai điều này. Việc sử dụng sản xuất chỉ nên dựa trên các bản phát hành chính thức của máy chủ và các trình điều khiển được hỗ trợ.