如何使用 Rails 在 MongoDB 中验证跨模型的唯一性?

Posted

技术标签:

【中文标题】如何使用 Rails 在 MongoDB 中验证跨模型的唯一性?【英文标题】:How to validate uniquness across models in MongoDB with Rails? 【发布时间】:2020-11-15 08:23:45 【问题描述】:

在我的 rails 应用程序中,我使用 MongoDB。我有 4 个模型,包括管理员。所有实体都有一个电子邮件地址。我需要进行验证以确保电子邮件对于所有模型都是唯一的。

除了在每个模型中搜索电子邮件之外,还有更简单/更好的方法吗?

喜欢


 def email_uniquness_across_models(email)
    User.where(email: email).exists? ||
      Admin.where(email: email).exists? ||
      Transporter.where(email: email).exists? ||
      Company.where(email: email).exists?
  end

【问题讨论】:

在 MongoDB 中,连接的等价物是 $lookup,$exists 是 SQL EXIST 关键字的等价物。但我什至不确定它是否可能。 您可能想尝试提出单独的问题或将问题重新表述为 MongoDB 问题,因为他们在数据库本身方面的专家比 Mongoid 的专家要多得多。 可以创建一个具有来自所有 4 个模型的公共字段的继承模型,并可以对其进行验证。此外,您不需要写 where 查询,因为键是唯一的,所以只需 User.find_by(email: email).present? || Admin.find_by(email: email).present?应该做的伎俩。 就代码复杂度而言,lookup 版本比您当前的每个模型调用一次exists? 要差得多。 这取决于这种独特性的重要性......因为如果它至关重要,您将需要实现互斥锁。 【参考方案1】:

您可以创建一个额外的模型和集合,其工作是存储电子邮件地址,并在那里添加一个唯一索引。创建新用户/管理员/运输商/公司时,首先在此集合中创建一个文档,如果成功,则在其他模型之一中使用相同的电子邮件地址。

【讨论】:

【参考方案2】:

如果您设置保持模型不变,并且必须在 4 个集合之间保持电子邮件的唯一性,我将在其自己的集合中创建一个电子邮件模型,并在电子邮件字段上定义一个唯一索引:

class Email
  include Mongoid::Document

  field :email, type: String
  index(email: 1, unique: true)
end

这样,您所要做的就是尝试创建该电子邮件模型。如果您成功了,您可以继续创建您想要的特定模型,因为您知道电子邮件在所有模型中都是独一无二的。 (这个建议类似于@huzaifa-saifuddin 的建议,但没有将所有模型合并到一个集合中)

那么唯一性方法定义将对数据库进行一次调用,如下所示:

def email_uniquness_across_models(email)
  Email.create(email: email)
  true
rescue
  false
end

恕我直言,最好对数据库进行一次调用以确保唯一性,而不是在大多数时间确保唯一性的 4 次调用。

此实现将确保唯一性,但您还必须处理故障 - 即处理后续模型创建失败的情况,您现在需要删除电子邮件文档,以便特定电子邮件可用。

【讨论】:

以上是关于如何使用 Rails 在 MongoDB 中验证跨模型的唯一性?的主要内容,如果未能解决你的问题,请参考以下文章

如何将内存中的 MongoDB 与 Rails、Mongoid 和 Rspec 一起使用?

如何避免在 MongoDB(使用 Mongoid)或 ActiveRecord(使用 MySQL 的 Rails)中插入两次相同的记录?

如何使用 MongoDB 和 Mongoid 在 Rails 3 上进行适当的数据库测试 (TDD)

如何使用 RSpec 在 Rails 中测试:包含验证

如何在 Rails 应用程序中使用用户密码验证帐户终止?

Rails:如何跨视图访问模型和控制器数据?