NAME
Elastic::Manual::Attributes::Unique - Making attributes unique
VERSION
version 0.52
INTRODUCTION
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.
STORING UNIQUE KEYS
Elastic::Model adds support for unique constraints other than the ID. Your unique attributes are tracked in a special index which defaults to "unique_key"
, but which can be specified in your Model class:
package MyApp;
use Elastic::Model;
has_namespace 'foo' .....;
has_unique_index 'myapp_uniques';
The index will be created automatically.
APPLYING UNIQUE CONSTRAINTS
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
.
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
.
COMPOUND KEYS
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:
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 doc is saved after either the account_type
or account_name
is changed, the account_key
will be checked for uniqueness.
HANDLING CONFLICTS
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:
{
account_key => 'facebook:joe_bloggs'
}
INCOMPATIBILITIES
$doc->overwrite()
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.
$view->delete
If you use "delete()" in Elastic::Model::View then you are responsible for removing the related keys yourself.
Changing unique key names and reindexing
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.
SEE ALSO
AUTHOR
Clinton Gormley <drtech@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2015 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.