如何在没有路径冲突的情况下优雅地 PATCH 更改为 mongodb

How to elegantly PATCH changes into mongodb without path conflicts

所以我试图通过 向 MongoDB 商店发出 PATCH 请求。这是数据的样子:

const booksSchema = mongoose.Schema(
  {
    name: { type: String, trim: true },
    author: { type: String, trim: true },
  },
  { timestamps: true },
)
const Book = mongoose.model('Book', bookSchema)

const librarySchema = mongoose.Schema(
  { books: [ Books.schema ] },
  { timestamps: true },
)
const Library = mongoose.model('Library', librarySchema)

这就是我更新数据的方式:

  const library = await Library.findOneAndUpdate(
    { _id: libraryId, "books._id": bookId },
    { $set: { "books.$": bookBody } },
  )

在这个过程中,我 运行 遇到了 automated timestamp update conflicting with the $set command 的问题:

Updating the path 'books.$.updatedAt' would create a conflict at 'books.$'

我遇到的在不删除自动时间戳更新的情况下进行此类更新的最佳解决方案是 manually set each field,如下所示:

  const library = await Library.findOneAndUpdate(
    { _id: libraryId, "book._id": bookId },
    {
      $set: {
        "book.$.name": bookBody.name,
        "book.$.author": bookBody.author,
      }
    },
  )

...但是这个解决方案非常冗长。

是否有更优雅的方法来执行此类 PATCH 请求,也许使用某种对象解构,不需要维护每个字段的映射?

事实上,如果您打算按照 HTTP 协议中描述的方式执行 PATCH 操作:

The HTTP PATCH request method applies partial modifications to a resource.

来源:https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH

在您的情况下,您应该使用“详细”解决方案,因为您的替代更新 { $set: { "books.$": bookBody } } 将删除更新书中更新中缺少的任何 属性。这不是 PATCH 应该如何工作,而是 PUT 应该如何工作。

您可以通过引入一个辅助函数来执行类似这样的操作(示例使用 lodash),从而使您的代码不那么冗长:

import _ from 'lodash'

_.mapValues(book, (value) => {
   _.mapKeys(value, (innerValue, innerKey) => (
     `book.$.${innerKey}`
   )
)