在猫鼬中使用 save() 方法更新子文档不会保存在数据库中并且没有显示错误
Updating sub document using save() method in mongoose does not get saved in database and shows no error
我有一个像这样的 Mongoose 模型:
const centerSchema = mongoose.Schema({
centerName: {
type: String,
required: true,
},
candidates: [
{
candidateName: String,
voteReceived: {
type: Number,
default: 0,
},
candidateQR: {
type: String,
default: null,
},
},
],
totalVote: {
type: Number,
default: 0,
},
centerQR: String,
});
我有一个这样的 Node.JS 控制器功能:
exports.createCenter = async (req, res, next) => {
const newCenter = await Center.create(req.body);
newCenter.candidates.forEach(async (candidate, i) => {
const candidateQRGen = await promisify(qrCode.toDataURL)(
candidate._id.toString()
);
candidate.candidateQR = candidateQRGen;
// ** Tried these: **
// newCenter.markModified("candidates." + i);
// candidate.markModified("candidateQR");
});
// * Also tried this *
// newCenter.markModified("candidates");
const upDatedCenter = await newCenter.save();
res.status(201).json(upDatedCenter);
};
很简单,我想修改子文档上的candidateQR字段。结果应该是这样的:
{
"centerName": "Omuk Center",
"candidates": [
{
"candidateName": "A",
"voteReceived": 0,
"candidateQR": "some random qr code text",
"_id": "624433fc5bd40f70a4fda276"
},
{
"candidateName": "B",
"voteReceived": 0,
"candidateQR": "some random qr code text",
"_id": "624433fc5bd40f70a4fda277"
},
{
"candidateName": "C",
"voteReceived": 0,
"candidateQR": "some random qr code text",
"_id": "624433fc5bd40f70a4fda278"
}
],
"totalVote": 0,
"_id": "624433fc5bd40f70a4fda275",
"__v": 1,
}
但我得到的候选QR 在数据库中仍然为空。我试过 markModified() 方法。但这没有帮助(显示在上面代码的注释部分)。我没有收到任何错误消息。作为回应,我得到了预期的结果。但该结果并未保存在数据库中。我只想更改 candidateQR 字段。但是想不通。
据我了解,您只是循环遍历候选人数组,但您
不存储更新的数组。您还需要将更新的数据存储在变量中。请使用地图尝试以下解决方案。
exports.createCenter = async (req, res, next) => {
const newCenter = await Center.create(req.body);
let candidates = newCenter.candidates;
candidates = candidates.map(candidate => {
const candidateQRGen = await promisify(qrCode.toDataURL)(
candidate._id.toString()
);
return {
...candidate,
candidateQR: candidateQRGen
}
});
newCenter.candidates = candidates;
const upDatedCenter = await newCenter.save();
res.status(201).json(upDatedCenter);
};
你可以在save()
之前使用这个
newCenter.markModified('candidates');
您可以使用 eachSeries 而不是 forEach 循环。
const async = require("async");
exports.createCenter = async (req, res, next) => {
const newCenter = await Center.create(req.body);
async.eachSeries(newCenter.candidates, async (candidate, done) => {
const candidateQRGen = await promisify(qrCode.toDataURL)(
candidate._id.toString(),
);
candidate.candidateQR = candidateQRGen;
newCenter.markModified("candidates");
await newCenter.save(done);
});
res.status(201).json(newCenter);
};
forEach 循环是这里的罪魁祸首。用 for...of 替换 forEach 后,问题就解决了。基本上,forEach 接受一个回调函数,该函数在代码库中被标记为异步,returns 最初是一个 Promise,稍后会执行。
As for...of 没有接受任何回调函数,所以它里面的 await 属于控制器函数的范围并立即执行。感谢 Indraraj26 指出这一点。所以,控制器的最终工作版本应该是这样的:
exports.createCenter = async (req, res, next) => {
const newCenter = await Center.create(req.body);
for(const candidate of newCenter.candidates) {
const candidateQRGen = await promisify(qrCode.toDataURL)(
candidate._id.toString()
);
candidate.candidateQR = candidateQRGen;
};
newCenter.markModified("candidates");
const upDatedCenter = await newCenter.save();
res.status(201).json(upDatedCenter);
};
另外,感谢 Moniruzzaman Dipto 展示使用 async.eachSeries() 方法解决问题的不同方法。
我有一个像这样的 Mongoose 模型:
const centerSchema = mongoose.Schema({
centerName: {
type: String,
required: true,
},
candidates: [
{
candidateName: String,
voteReceived: {
type: Number,
default: 0,
},
candidateQR: {
type: String,
default: null,
},
},
],
totalVote: {
type: Number,
default: 0,
},
centerQR: String,
});
我有一个这样的 Node.JS 控制器功能:
exports.createCenter = async (req, res, next) => {
const newCenter = await Center.create(req.body);
newCenter.candidates.forEach(async (candidate, i) => {
const candidateQRGen = await promisify(qrCode.toDataURL)(
candidate._id.toString()
);
candidate.candidateQR = candidateQRGen;
// ** Tried these: **
// newCenter.markModified("candidates." + i);
// candidate.markModified("candidateQR");
});
// * Also tried this *
// newCenter.markModified("candidates");
const upDatedCenter = await newCenter.save();
res.status(201).json(upDatedCenter);
};
很简单,我想修改子文档上的candidateQR字段。结果应该是这样的:
{
"centerName": "Omuk Center",
"candidates": [
{
"candidateName": "A",
"voteReceived": 0,
"candidateQR": "some random qr code text",
"_id": "624433fc5bd40f70a4fda276"
},
{
"candidateName": "B",
"voteReceived": 0,
"candidateQR": "some random qr code text",
"_id": "624433fc5bd40f70a4fda277"
},
{
"candidateName": "C",
"voteReceived": 0,
"candidateQR": "some random qr code text",
"_id": "624433fc5bd40f70a4fda278"
}
],
"totalVote": 0,
"_id": "624433fc5bd40f70a4fda275",
"__v": 1,
}
但我得到的候选QR 在数据库中仍然为空。我试过 markModified() 方法。但这没有帮助(显示在上面代码的注释部分)。我没有收到任何错误消息。作为回应,我得到了预期的结果。但该结果并未保存在数据库中。我只想更改 candidateQR 字段。但是想不通。
据我了解,您只是循环遍历候选人数组,但您 不存储更新的数组。您还需要将更新的数据存储在变量中。请使用地图尝试以下解决方案。
exports.createCenter = async (req, res, next) => {
const newCenter = await Center.create(req.body);
let candidates = newCenter.candidates;
candidates = candidates.map(candidate => {
const candidateQRGen = await promisify(qrCode.toDataURL)(
candidate._id.toString()
);
return {
...candidate,
candidateQR: candidateQRGen
}
});
newCenter.candidates = candidates;
const upDatedCenter = await newCenter.save();
res.status(201).json(upDatedCenter);
};
你可以在save()
newCenter.markModified('candidates');
您可以使用 eachSeries 而不是 forEach 循环。
const async = require("async");
exports.createCenter = async (req, res, next) => {
const newCenter = await Center.create(req.body);
async.eachSeries(newCenter.candidates, async (candidate, done) => {
const candidateQRGen = await promisify(qrCode.toDataURL)(
candidate._id.toString(),
);
candidate.candidateQR = candidateQRGen;
newCenter.markModified("candidates");
await newCenter.save(done);
});
res.status(201).json(newCenter);
};
forEach 循环是这里的罪魁祸首。用 for...of 替换 forEach 后,问题就解决了。基本上,forEach 接受一个回调函数,该函数在代码库中被标记为异步,returns 最初是一个 Promise,稍后会执行。
As for...of 没有接受任何回调函数,所以它里面的 await 属于控制器函数的范围并立即执行。感谢 Indraraj26 指出这一点。所以,控制器的最终工作版本应该是这样的:
exports.createCenter = async (req, res, next) => {
const newCenter = await Center.create(req.body);
for(const candidate of newCenter.candidates) {
const candidateQRGen = await promisify(qrCode.toDataURL)(
candidate._id.toString()
);
candidate.candidateQR = candidateQRGen;
};
newCenter.markModified("candidates");
const upDatedCenter = await newCenter.save();
res.status(201).json(upDatedCenter);
};
另外,感谢 Moniruzzaman Dipto 展示使用 async.eachSeries() 方法解决问题的不同方法。