【问题标题】:Mongoose pre save not update fieldMongoose 预保存不更新字段
【发布时间】:2021-08-14 22:17:30
【问题描述】:

我有一个像这样的视频架构:

const videoSchema = new mongoose.Schema({
    cover: { // image url
        type: String,
        required: true,
    },
    category: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Category'
    }],
})

当我创建新视频时,我将从第三个站点获取封面图片并将其保存到 AWS S3,然后更新新的封面网址。我有这样的预存中间件

videoSchema.pre("save", async function save(next) {
    try {
        await transferImagesToS3(this.cover, async (err, resp) => {
            if (err) {
                next()
            }
            if (resp.Location) { // image uploaded to AWS S3 and return new image url here
                this.cover = resp.Location // I set new url here
                next()
            }
        })
    } catch (err) {
        next(err)
    }
}) 

传输图像功能

// transfer image to S3
export const transferImagesToS3 = (imgURL, filename, callback) => {
    request({
        url: imgURL,
        encoding: null
    }, function (err, res, body) {
        if (err) return callback(err, res);

        s3.upload({
            Bucket: 'mybucket',
            Key: `public/images/${filename}.jpeg`,
            cacheControl: 'max-age=604800',
            ContentType: res.headers['content-type'],
            ContentLength: res.headers['content-length'],
            Body: body // buffer
        }, callback)
    })
}

以上代码,this.cover 是来自第三个网站的图片网址。图片上传成功,但预保存未更新新图片网址。这段代码有什么问题?你能帮帮我吗?

谢谢

【问题讨论】:

  • 它显示了我想要的新 URL,但我不知道为什么在 DB 中,它没有更新。
  • 是的,它是展示视频文件。只是没有保存到数据库中。

标签: javascript node.js mongodb mongoose


【解决方案1】:

您将callback 样式与async/await 样式混合在一起。 async 函数总是返回一个 Promise,在您的情况下,async function save(next) 将返回一个 Promise,而 hook 将在 Promise 解决后立即“完成”。

Mongoose middleware doc.

我猜你希望钩子会等到transferImagesToS3 完成,然后进入下一个过程。但实际上,您的 await 关键字没有意义,因为 transferImagesToS3 不会返回 Promise(我是客人)。

我们有两种解决方案:

  1. 只使用回调样式:
videoSchema.pre("save", function (next) { // remove async
  transferImagesToS3(this.cover, (err, resp) => { // remove await, async
    if (err) {
      next() // next(err) when you want to stop when upload is failed
    }
    if (resp.Location) { // image uploaded to AWS S3 and return new image url here
      this.cover = resp.Location // I set new url here
      next()
    }
  })
})
  1. 转换 transferImagesToS3 以返回 Promise(我推荐):

我使用promisify 将回调函数转换为返回Promise。

const util = require('util')

videoSchema.pre("save", async function () { // remove next
  const resp = await util.promisify(transferImagesToS3)(this.cover) // wait
  this.cover = resp.Location
})

【讨论】:

  • 非常感谢,我尝试了方法 1,效果很好!我还是 nodejs 的新手,仍然对承诺感到困惑。我更新了我的问题,添加了transferImagesToS3 函数。如何将其转换为承诺?
猜你喜欢
  • 2017-12-07
  • 2021-06-21
  • 2018-06-29
  • 2013-12-29
  • 1970-01-01
  • 2020-05-13
  • 2015-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多