在猫鼬中使用 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,稍后会执行。

A​​s 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() 方法解决问题的不同方法。