Elastic::Manual::Attributes::Unique - Making attributes unique
version 0.27
The only unique constraint available in Elasticsearch is the document ID. Typically, if you want a document to be unique, you use the unique value as the ID.
However, sometimes you don't want to do this. For instance, you may want to use the email address as a unique constraint for your user accounts, but you also want to be able to link to a user account without exposing their email address, and let the user change their email address without having to update the ID of their user account wherever it is used.
In this case, we want the ID of the user document to be auto-generated, but we also want the value of the email attribute to be unique.
email
Elastic::Model uses ElasticSearchX::UniqueKey to enable unique constraints. Your unique attributes are tracked in a special index which defaults to "unique_key", but which can be specified in your Model class:
"unique_key"
package MyApp; use Elastic::Model; has_namespace 'foo' .....; has_unique_index 'myapp_uniques';
The index will be created automatically.
Any attribute whose value is a string (including numeric attributes) can have a unique constraint applied:
has 'email' => ( is => 'rw', isa => 'Str', unique_key => 'myapp_email' );
The unique_key value will be used as the type in the unique keys index. For instance, if the email is john@foo.com, then the unique entry for this document will be stored in index:myapp_uniques, under type:myapp_email with id:john@foo.com.
unique_key
type
john@foo.com
index:myapp_uniques
type:myapp_email
id:john@foo.com
The unique_key can only be used once in a doc class. You can't have (eg) the attributes email_1 and email_2 both using a unique_key of myapp_email.
email_1
email_2
myapp_email
It is easy to make a compound key a unique constraint. For instance, to combine the attributes account_type and account_name you could do:
account_type
account_name
has 'account_type' => ( is => 'rw', isa => 'Str', required => 1, trigger => sub { shift->clear_account_key } ); has 'account_name' => ( is => 'rw', isa => 'Str', required => 1, trigger => sub { shift->clear_account_key } ); has 'account_key' => ( is => 'ro', isa => 'Str', init_arg => undef, lazy => 1, unique_key => 'account_key', builder => '_build_account_key', clearer => 'clear_account_key', ); sub _build_account_key { my $self = shift; return $self->account_type . ':' .$self->account_name }
When the docs is saved after either the account_type or account_name is changed, the account_key will be checked for uniqueness.
account_key
When you save a doc, any unique keys will be checked for uniqueness, and an error will be thrown if there is a conflict.
You can handle these error gracefully using the on_unique parameter:
$doc->save( on_unique => sub { my ($doc,$failed) = @_; # do something } )
The $failed hashref will contain a hashref whose keys are the name of the unique_keys that have conflicts, and whose values are the values of those keys which already exist, and so cannot be overwritten. For instance:
$failed
{ account_key => 'facebook:joe_bloggs' }
You can't overwrite a doc with unique keys that hasn't already been loaded from Elasticsearch. For instance, you can do:
$user = $domain->get( user => 1 ); $user->email('jack@foo.com'); $user->overwrite;
But not:
$user = $domain->new_doc( user => { id => 1, email => 'jack@foo.com' }); $user->overwrite;
The reason for this is that, if that user already exists, then overwriting that doc will leave any old unique keys in place. "save()" in Elastic::Model::Role::Doc will handle the old unique values correctly.
If you use "delete()" in Elastic::Model::View then you are responsible for removing the related keys yourself.
The unique keys index will not be updated if you change the unique_key name, and reindexing does not take unique keys into account at all. It is up to you to manage any changes.
ElasticSearchX::UniqueKey
Elastic::Manual::Attributes
Elastic::Model
Elastic::Manual
Clinton Gormley <drtech@cpan.org>
This software is copyright (c) 2013 by Clinton Gormley.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
To install Elastic::Model, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Elastic::Model
CPAN shell
perl -MCPAN -e shell install Elastic::Model
For more information on module installation, please visit the detailed CPAN module installation guide.