英文:
Fail to update Mongodb nested object using Mongoose
问题
我的架构:
```javascript
import pkg from "mongoose";
const { Schema, model, models } = pkg;
const child = new Schema({ name: String, studentid: Number});
const schema = new Schema({ name: String, age: Number, children: [child] });
const Test = model("Test", schema)
export default Test;
数据示例:
我的更新函数,我希望根据 age
和 studentid
更新数组中整个对象:
import { connectToDB } from "./utils/database.js";
import Test from "./models/test.js";
async function updateData() {
await connectToDB();
const res = Test.updateMany(
{
age: 34,
name: "name2",
},
{
$set: {
"children.$[element]": {
name: "updatedname",
studentid: 123456789,
},
},
},
{
arrayFilters: [
{
element: {
name: "childr344en1",
studentid: 137,
},
},
],
},
{upsert: true}
);
console.log(res)
}
await updateData();
执行更新函数后,数据未更新。请问原因在哪里?我做错了什么吗?
<details>
<summary>英文:</summary>
My schema:
```javascript
import pkg from "mongoose";
const { Schema, model, models } = pkg;
const child = new Schema({ name: String, studentid: Number});
const schema = new Schema({ name: String, age: Number, children: [child] });
const Test = model("Test", schema)
export default Test;
Data sample:
My update function, I wish to update the entire object inside the array base on age
and studentid
:
import { connectToDB } from "./utils/database.js";
import Test from "./models/test.js";
async function updateData() {
await connectToDB();
const res = Test.updateMany(
{
age: 34,
name: "name2",
},
{
$set: {
"children.$[element]": {
name: "updatedname",
studentid: 123456789,
},
},
},
{
arrayFilters: [
{
element: {
name: "childr344en1",
studentid: 137,
},
},
],
},
{upsert: true}
);
console.log(res)
}
await updateData();
After executing the update function, the data didn't update. May I ask why? Where am I doing wrong?
答案1
得分: 2
以下是翻译的内容:
由于child
是嵌套在children
字段中的subdocuments,子文档将具有一个_id
字段。例如,子文档是
{ name: 'children1', studentid: 13, _id: ObjectId("649d778bc678b80c6073e487") }
但arrayFilters
是[{ element: { name: 'children1', studentid: 13 }}]
,它不会匹配子文档。这就是为什么arrayFilters
不起作用的原因。
如果您不关心子文档的_id
,可以使用两个字段来匹配子文档:element.name
和element.studentid
。
或者像这样使用整个子文档:
{
arrayFilters: [{ element: t2.children[0] }]
}
// t2.children[0] => { name: 'childr344en1', studentid: 137, _id: ObjectId("649d7aa53c3e28bda4c758e3") }
希望这对您有所帮助。
英文:
Since the child
is subdocuments embedded in the children
field. The subdocument will have a _id
field. For example, the subdocument is
{ name: 'children1', studentid: 13, _id: ObjectId("649d778bc678b80c6073e487") }
But the arrayFilters
is [{ element: { name: 'children1', studentid: 13 }}]
, it will not match the subdocument. That's why the arrayFilters
does not work.
You can match the subdocument using two fields: element.name
and element.studentid
if you don't care about the _id
of the subdocument.
Or use the entire subdocument like:
{
arrayFilters: [{ element: t2.children[0] }]
}
// t2.children[0] => { name: 'childr344en1', studentid: 137, _id: ObjectId("649d7aa53c3e28bda4c758e3") }
E.g.
import mongoose from 'mongoose';
import { config } from '../../config';
mongoose.set('debug', true);
const child = new mongoose.Schema({ name: String, studentid: Number });
const schema = new mongoose.Schema({ name: String, age: Number, children: [child] });
const Test = mongoose.model('Test', schema);
(async function main() {
try {
await mongoose.connect(config.MONGODB_URI);
await Test.collection.drop();
// seed
const [, t2] = await Test.create([
{ name: 'name1', age: 14, children: [{ name: 'children1', studentid: 13 }] },
{
name: 'name2',
age: 34,
children: [
{ name: 'childr344en1', studentid: 137 },
{ name: 'children2', studentid: 14 },
],
},
]);
const res = await Test.updateMany(
{
name: 'name2',
age: 34,
},
{
$set: {
'children.$[element]': {
name: 'updatedname',
studentid: 123456789,
},
},
},
{
arrayFilters: [
{
'element.name': 'childr344en1',
'element.studentid': 137,
},
],
upsert: true,
},
);
console.log(res);
const r = await Test.findOne({ name: 'name2', age: 34 }).select({ __v: 0 });
console.log(r?.toObject());
} catch (error) {
console.error(error);
} finally {
await mongoose.connection.close();
}
})();
Debug logs:
Mongoose: tests.drop()
Mongoose: tests.insertOne({ name: 'name1', age: 14, children: [ { name: 'children1', studentid: 13, _id: ObjectId("649d795086edc01df88090ea") } ], _id: ObjectId("649d795086edc01df88090e9"), __v: 0}, {})
Mongoose: tests.insertOne({ name: 'name2', age: 34, children: [ { name: 'childr344en1', studentid: 137, _id: ObjectId("649d795086edc01df88090ec") }, { name: 'children2', studentid: 14, _id: ObjectId("649d795086edc01df88090ed") } ], _id: ObjectId("649d795086edc01df88090eb"), __v: 0}, {})
Mongoose: tests.updateMany({ name: 'name2', age: 34 }, { '$setOnInsert': { __v: 0 }, '$set': { 'children.$[element]': { name: 'updatedname', studentid: 123456789, _id: ObjectId("649d795186edc01df88090f0") } }}, { arrayFilters: [ { 'element.name': 'childr344en1', 'element.studentid': 137 } ], upsert: true})
{
acknowledged: true,
modifiedCount: 1,
upsertedId: null,
upsertedCount: 0,
matchedCount: 1
}
Mongoose: tests.findOne({ name: 'name2', age: 34 }, { projection: { __v: 0 } })
{
_id: new ObjectId("649d795086edc01df88090eb"),
name: 'name2',
age: 34,
children: [
{
name: 'updatedname',
studentid: 123456789,
_id: new ObjectId("649d795186edc01df88090f0")
},
{
name: 'children2',
studentid: 14,
_id: new ObjectId("649d795086edc01df88090ed")
}
]
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论