如何通过一个更新查询保证唯一的主键

时间:2019-02-18 10:11:06

标签: mongodb mongoose

在我的电影模式中,我有一个“ release_date”字段,可以包含嵌套的子文档。

这些子文档包含三个字段:

  • 国家/地区代码
  • 日期
  • 细节

我需要确保前两个字段是唯一的(主键)。

我首先尝试设置一个唯一索引。但是我终于意识到,MongoDB不支持子文档上的唯一索引。 索引已创建,但是验证不会触发,我仍然可以添加重复项。

然后,我尝试修改我的更新功能以防止重复,如本文所述(请参阅替代方法):http://joegornick.com/2012/10/25/mongodb-unique-indexes-on-single-embedded-documents/

$ ne效果很好,但就我而言,我将两个字段组合在一起,而且这是一种更加复杂的方式...

$ addToSet很不错,但不是我要搜索的内容,因为“详细信息”字段可能不是唯一的。

我还尝试了像mongoose-unique-validator这样的插件,但是它不适用于子文档...

我最终遇到了两个查询。一个用于搜索现有子文档,如果先前的查询未返回任何文档,则另一个用于添加子文档。

insertReleaseDate: async(root, args) => {
  const { movieId, fields } = args

  // Searching for an existing primary key
  const document = await Movie.find(
    {
      _id: movieId,
      release_date: {
        $elemMatch: {
          country_code: fields.country_code,
          date: fields.date
        }
      }
    }
  )

  if (document.length > 0) {
    throw new Error('Duplicate error')
  }

  // Updating the document
  const response = await Movie.updateOne(
    { _id: movieId },
    { $push: { release_date: fields } }
  )

  return response
}

这段代码可以正常工作,但我宁愿只使用一个查询。

有什么主意吗?我不明白为什么它这么复杂,应该经常使用。

1 个答案:

答案 0 :(得分:0)

感谢RichieK的回答!效果很好。

请小心将字段名放在“ $ not”之前,如下所示:

insertReleaseDate: async(root, args) => {
  const { movieId, fields } = args

  const response = await Movie.updateOne(
    {
      _id: movieId,
      release_date: {
        $not: {
          $elemMatch: {
            country_code: fields.country_code,
            date: fields.date
          }
        }
      }
    },
    { $push: { release_date: fields } }
  )

  return formatResponse(response, movieId)
}

非常感谢!