我有以下型号
class Person
include Mongoid::Document
embeds_many :tasks
end
class Task
include Mongoid::Document
embedded_in :commit, :inverse_of => :tasks
field :name
end
我如何确保以下内容?
person.tasks.create :name => "create facebook killer"
person.tasks.create :name => "create facebook killer"
person.tasks.count == 1
different_person.tasks.create :name => "create facebook killer"
person.tasks.count == 1
different_person.tasks.count == 1
即。任务名称在特定人员中是唯一的
检查了索引上的文档后,我认为以下内容可能有效:
class Person
include Mongoid::Document
embeds_many :tasks
index [
["tasks.name", Mongo::ASCENDING],
["_id", Mongo::ASCENDING]
], :unique => true
end
但是
person.tasks.create :name => "create facebook killer"
person.tasks.create :name => "create facebook killer"
仍然会产生重复。
上面显示的Person中的索引配置将转换为mongodb
db.things.ensureIndex({firstname : 1, 'tasks.name' : 1}, {unique : true})
答案 0 :(得分:5)
难道你不能在任务上放一个验证器吗?
validates :name, :uniqueness => true
这应确保父文档中的唯一性。
答案 1 :(得分:1)
默认情况下,索引不是唯一的。如果你看一下这里的Mongo Docs,唯一性是一个额外的标志。
我不知道确切的Mongoid翻译,但你正在寻找这样的东西:
db.things.ensureIndex({firstname : 1}, {unique : true, dropDups : true})
答案 2 :(得分:0)
我不相信嵌入式文档可以实现这一点。我遇到了和你一样的问题,我找到的唯一解决方法是使用引用的文档,而不是嵌入的文档,然后在引用的文档上创建复合索引。
显然,唯一性验证是不够的,因为它不能防范竞争条件。我遇到的唯一索引的另一个问题是,如果验证通过并且数据库拒绝接受该文档,则mongoid的默认行为是不会引发任何错误。我不得不在mongoid.yml中更改以下配置选项:
persist_in_safe_mode: true
这在http://mongoid.org/docs/installation/configuration.html
中有记录最后,在进行此更改后,如果数据库拒绝存储文档,则save / create方法将开始抛出错误。所以,你需要这样的东西才能告诉用户发生的事情:
alias_method :explosive_save, :save
def save
begin
explosive_save
rescue Exception => e
logger.warn("Unable to save record: #{self.to_yaml}. Error: #{e}")
errors[:base] << "Please correct the errors in your form"
false
end
end
即使这不是一个很好的选择,因为你还在猜测哪些字段确实导致错误(以及为什么)。更好的解决方案是查看MongoidError并相应地创建正确的错误消息。以上适合我的申请,所以我没有走那么远。
答案 3 :(得分:0)
添加验证检查,将嵌入任务ID的数组计数与具有唯一ID的另一个数组的计数进行比较。
validates_each :tasks do |record, attr, tasks|
ids = tasks.map { |t| t._id }
record.errors.add :tasks, "Cannot have the same task more than once." unless ids.count == ids.uniq.count
end
为我工作。
答案 4 :(得分:0)
您可以在任务模型上定义validates_uniqueness_of以确保这一点,根据http://mongoid.org/docs/validation.html处的Mongoid文档,此验证适用于父文档的范围,并且应该执行您想要的操作。
您的索引技术也应该有效,但您必须在它们生效之前生成索引。使用Rails,您可以使用rake任务执行此操作(在当前版本的Mongoid中称为db:mongoid:create_indexes)。请注意,保存违反索引约束的内容时不会出现错误,因为Mongoid(有关详细信息,请参阅http://mongoid.org/docs/persistence/safe_mode.html)。
答案 5 :(得分:0)
您还可以在模型类中指定索引:
index({ 'firstname' => 1, 'tasks.name' => 1}, {unique : true, drop_dups: true })
并使用rake任务
rake db:mongoid:create_indexes
答案 6 :(得分:-1)
你必须跑:
db.things.ensureIndex({firstname : 1, 'tasks.name' : 1}, {unique : true})
直接在数据库上
您似乎在“活动记录”中包含“创建索引命令”(即类人员)