0

我正在为纸质音乐杂志建立我的第一个个人项目,为他们的订阅者提供在线阅读。我已经知道我将不得不将大量重复的代码重构为可重用的代码,但我现在只想让事情正常工作。

这些是我用来构建模型/控制器的集合:

  • 艺术家
  • 相册
  • 用户(管理员、作者、订阅者)
  • 编年史(专辑短评)
  • 文章(专辑长评)
  • 采访(大部分时间与文章相关)
  • 问题,参考所有编年史、文章和访谈(ObjectID 数组)

Artist简单明了,只有 'name'、'country' 和一个空的 'albums' 数组:

exports.createArtist = catchAsync(async (req, res, next) => {
  req.body.createdBy = mongoose.Types.ObjectId(req.user._id)
  req.body.albums = []
  const newArtist = await Artist.create(req.body)

  res.status(201).json({
    status: 'success',
    data: {
      article: newArtist,
    },
  })
})

专辑有点复杂,但艺术家“姓名”被转换为其 ObjectId 以供参考,并使用新创建的专辑 ObjectId 填充艺术家的“专辑”数组

exports.createAlbum = catchAsync(async (req, res, next) => {
  // Add createdBy automatically in the req.body
  req.body.createdBy = mongoose.Types.ObjectId(req.user._id)

  // Find the album's artist by its name
  const relatedArtist = await Artist.findOne({ name: req.body.artist })

  if (!relatedArtist) {
    return next(new AppError('No artist with that name, please check', 404))
  }
  // replace the name of the artist with its objectID for auto referencing
  req.body.artist = mongoose.Types.ObjectId(relatedArtist._id)

  // save album
  const newAlbum = await Album.create(req.body)

  // add the saved album into the albums' array in the artist collection
  relatedArtist.albums.push(mongoose.Types.ObjectId(newAlbum._id))
  await relatedArtist.save()

  res.status(201).json({
    status: 'success',
    data: {
      album: newAlbum,
    },
  })
})

Chronicle 有点相似,但在此过程中涉及其他 3 个集合:专辑和艺术家数据的集合,以及填充当前问题的“chronicles”数组:

exports.createChronicle = catchAsync(async (req, res, next) => {
  // Add author automatically in the req.body
  req.body.author = mongoose.Types.ObjectId(req.user._id)

  // Find artist & album of the chronicle in the respective collections
  const artist = await Artist.findOne({ name: req.body.artist })
  const album = await Album.findOne({ title: req.body.album })
  const issue = await Issue.findOne({ issueNumber: req.body.belongsToIssue })

  if (!artist) {
    return next(new AppError('No artist with that name, please check.', 404))
  }
  if (!album) {
    return next(new AppError('No album with that name, please check.', 404))
  }
  if (!issue) {
    return next(new AppError('No issue with that number, please check.', 404))
  }

  // replace the name of the artist and album with its objectID for auto referencing
  req.body.artist = mongoose.Types.ObjectId(artist._id)
  req.body.album = mongoose.Types.ObjectId(album._id)

  // Create Chronicle unique slug & add to req.body
  req.body.slug = slugify(`${artist.name} ${album.title} ${album.year}`, {
    lower: true,
  })

  // Save new Chronicle
  const newChronicle = await Chronicle.create(req.body)

  // Push new Chronicle ID into the array of the corresponding Issue
  issue.chronicles.push(mongoose.Types.ObjectId(newChronicle._id))
  await issue.save()

  res.status(201).json({
    status: 'success',
    data: {
      chronicle: newChronicle,
    },
  })
})

我的问题现在出现在“文章”上:一篇文章可以是关于几张专辑的(所以不仅仅是一个 ObjectId,而是一个 ObjectId 数组!)并且可以由多个作者(1 到 3 之间)签名。每次执行时我都必须遍历两个数组:

await Album.find({title: req.body.title})
await User.find({author: req.body.author})

然后通过其 ObjectId 交换 req.body.albums 和 req.body.authors 中的名称,最后将 req.body.albums + authors 从字符串数组转换为 ObjectIds 数组,尤其是在数组是指针的情况下(我猜我必须使用解构的重复数组)。我知道我无法在map()循环的forEach()中执行异步操作,但还没有弄清楚如何使它工作。我的研究使我认为我必须使用Promise.all()但到目前为止还没有弄清楚如何使用,直到现在我所有的试验和错误都失败了,所以我必须以错误的方式执行此操作或不了解该过程。

感谢您的帮助和技巧!

4

1 回答 1

0

谢谢阿纳托利。您的提示使我发现了一些需要优化和重构的东西,但它具有完全功能性的巨大优势:

exports.createArticle = catchAsync(async (req, res, next) => {
  // Add authors automatically in the req.body if not specified by user
  if (!req.body.authors || req.body.authors === []) {
    req.body.authors.push(mongoose.Types.ObjectId(req.user._id))
  }

  // loop through all authors names and swap with respective ObjectIds
  const tempAuthors = []
  await Promise.all(
    req.body.authors.map(async (author, index) => {
      const user = await User.findOne({ name: author })
      if (!user) {
        return next(
          new AppError(
            `No author with that name (position ${index + 1}), please check.`,
            404
          )
        )
      }
      tempAuthors.push(mongoose.Types.ObjectId(user._id))
    })
  )

  // Assign req.body.authors the values of tempAuthors
  req.body.authors = [...tempAuthors]

  // loop through all album titles and swap with respective ObjectIds
  const tempAlbums = []
  await Promise.all(
    req.body.albums.map(async (title, index) => {
      const album = await Album.findOne({ title })
      if (!album) {
        return next(
          new AppError(
            `No album with that title (position ${index + 1}), please check.`,
            404
          )
        )
      }
      tempAlbums.push(mongoose.Types.ObjectId(album._id))
    })
  )

  // Assign req.body.authors the values of tempAuthors
  req.body.albums = [...tempAlbums]

  // Find artist & issue of the article
  const artist = await Artist.findOne({ name: req.body.artist })
  if (!artist) {
    return next(new AppError('No artist with that name, please check.', 404))
  }

  const issue = await Issue.findOne({ issueNumber: req.body.belongsToIssue })
  if (!issue) {
    return next(new AppError('No issue with that number, please check.', 404))
  }

  // replace the name of the artist with its objectID for auto referencing
  req.body.artist = mongoose.Types.ObjectId(artist._id)

  // Create Article unique slug & add to req.body
  req.body.slug = slugify(
    `${issue.issueNumber} ${artist.name} ${req.body.title}`,
    {
      lower: true,
    }
  )

  // Save new Article
  const newArticle = await Article.create(req.body)

  // Push new Article ID into the array of the corresponding Issue
  issue.articles.push(mongoose.Types.ObjectId(newArticle._id))
  await issue.save()

  res.status(201).json({
    status: 'success',
    data: {
      article: newArticle,
    },
  })
})

下一步将把专辑和作者的交换功能外包,以避免重复代码。

于 2021-01-24T12:01:19.520 回答