web-dev-qa-db-fra.com

DynamoDB - Insère un élément si le hachage (ou la combinaison de hachage et de plage) n'existe pas

Voici mes cas d'utilisation: J'ai une table Dynamo avec une clé de hachage + plage. Lorsque je mets de nouveaux éléments dans la table, je souhaite effectuer une vérification de l'unicité. Parfois, je veux garantir que le hachage est unique (en ignorant la plage). D'autres fois, je souhaite autoriser les doublons, mais je garantis que la combinaison de hachage et de plage est unique. Comment puis-je accomplir cela?

J'ai expérimenté attribut_not_exists. Il semble traiter le deuxième cas, où il vérifie la combinaison hash + key. Voici un exemple PHP:

$client->putItem(array(
    'TableName' => 'test',
    'Item' => array(
        'hash' => array('S' => 'abcdefg'),
        'range' => array('S' => 'some other value'),
        'whatever' => array('N' => 233)
    ),
    'ConditionExpression' => 'attribute_not_exists(hash)'
));

Bizarrement, peu importe si j'utilise attribute_not_exists(hash) ou attribute_not_exists(range). Ils semblent tous deux faire exactement la même chose. Est-ce ainsi que c'est censé fonctionner?

Une idée de comment gérer le cas où je veux seulement vérifier hash pour l'unicité?

18
mrog

Tu ne peux pas. Tous les éléments de DynamoDB sont indexés selon leur hash ou hash + range (en fonction de votre table).

Une sorte de résumé de ce qui se passe jusqu'à présent:

  • Une seule clé de hachage peut avoir plusieurs clés de plage.
  • Chaque élément a à la fois une clé hash et une clé range
  • Vous faites une demande PutItem et devez fournissez à la fois hash et range
  • Vous fournissez une ConditionExpression avec attribute_not_exists sur le nom de l'attribut hash ou range
  • La condition attribute_not_exists vérifie simplement si un attribut portant ce nom existe, peu importe la valeur

Passons en exemple. Commençons par une table de clés hash + range avec ces données:

  1. hash=A,range=1 
  2. hash=A,range=2

Il y a quatre cas possibles:

  1. Si vous essayez de placer un élément avec hash=A,range=3 et attribute_not_exists(hash), la PutItem réussira car attribute_not_exists(hash) est évalué à true. Aucun élément n'existe avec la clé hash=A,range=3 qui remplit la condition de attribute_not_exists(hash).

  2. Si vous essayez de placer un élément avec hash=A,range=3 et attribute_not_exists(range), la PutItem réussira car attribute_not_exists(range) est évalué à true. Aucun élément n'existe avec la clé hash=A,range=3 qui remplit la condition de attribute_not_exists(range).

  3. Si vous essayez de placer un élément avec hash=A,range=1 et attribute_not_exists(hash), la variable PutItem échouera car attribute_not_exists(hash) est évalué à false. Un élément existe avec la clé hash=A,range=1 qui ne répond pas à la condition de attribute_not_exists(hash).

  4. Si vous essayez de placer un élément avec hash=A,range=1 et attribute_not_exists(range), la variable PutItem échouera car attribute_not_exists(range) est évalué à false. Un élément existe avec la clé hash=A,range=1 qui ne répond pas à la condition de attribute_not_exists(range).

Cela signifie que l'une des deux choses va se passer:

  1. La paire hash + range existe dans la base de données.
    • attribute_not_exists(hash) doit être true
    • attribute_not_exists(range) doit être true
  2. La paire hash + range n'existe pas dans la base de données.
    • attribute_not_exists(hash) doit être false
    • attribute_not_exists(range) doit être false

Dans les deux cas, vous obtenez le même résultat, que vous le placiez sur la touche Dièse ou Plage. La clé hash + range identifie un seul élément de la table entière et votre condition est en cours d'évaluation sur cet élément.

Vous effectuez effectivement un "mettez cet élément si un élément avec cette clé hash + range n’existe pas déjà".

32
mkobit

Cette version de l'explication provient de Amazon aws forum indique qu'une recherche recherchera un élément qui correspond à une clé de hachage fournie, puis vérifie uniquement si l'attribut existe dans cet enregistrement. Cela devrait fonctionner de la même manière si vous avez un hash et une clé de plage, je suppose.

Si une requête tente de trouver un élément existant avec une clé de hachage "b825501b-60d3-4e53-b737-02645d27c2ae". Si c'est la première fois, cet identifiant est utilisé, il n'y aura pas d'article existant et "attribut_not_existe (email)" sera évalué à vrai, la demande de vente sera traverser. 

Si cet identifiant est déjà utilisé, il y aura un élément existant. Ensuite expression de condition recherchera un attribut de courrier électronique existant dans le fichier élément existant, s'il existe un attribut de courrier électronique, la demande de mise en place sera échec, s’il n’ya pas d’attribut email dans lequel la demande de vente sera traitée. 

Quoi qu'il en soit, il ne s'agit pas de comparer la valeur de l'attribut "email" et il s'agit de ne pas vérifier si d'autres éléments de la table utilisaient la même valeur "email".

Si l'email était la clé de hachage, alors request essaiera de trouver un fichier .__ existant. élément avec la clé de hachage "[email protected]". 

S'il existe un autre élément avec la même valeur de courrier électronique, un élément existant sera être trouvé. Puisque le courrier électronique est la clé de hachage, il doit être présent dans le fichier L'élément existant et "attribut_not_existe (email)" sera évalué à false et mettre la demande échouera.

Si "email", la valeur n'est pas utilisée avant que l'élément existant ne soit pas trouvé. et "attribut_not_exists (email)" sera évalué à true d'où Put demande va passer.

0
Jun711

Vous pouvez utiliser l'opération AND si votre table a hash et range

'ConditionExpression' => 'attribut_not_exists (dièse) ET attribut_not_exists (plage)'

0
Thaina

Attention avec mots-clés réservés .
attribute_not_exists ne fonctionnera pas comme prévu si le nom d'attribut fourni correspond à un mot de la liste réservée. hash et range sont tous deux réservés et nécessitent donc de contourner ce problème en utilisant ExpressionAttributeNames

L'exemple suivant autorise les clés de partition en double et n'échoue que s'il existe déjà un élément dans la table avec la clé de partition ET de partition fournie.

$client->putItem(array(
    'TableName' => 'test',
    'Item' => array(
        'hash' => array('S' => 'abcdefg'),
        'range' => array('S' => 'some other value'),
        'whatever' => array('N' => 233)
    ),
    'ConditionExpression' => 'attribute_not_exists(#h) AND attribute_not_exists(#r)',
    'ExpressionAttributeNames' => array('#h' => 'hash', '#r' => 'range')
));

Et celui-ci s’assurerait que la clé de partition nommée hash est unique.

 $client->putItem(
     'TableName' => 'test',
     'Item' => array(
        'hash' => array('S' => 'abcdefg'),
        'range' => array('S' => 'some other value'),
        'whatever' => array('N' => 233)
    ),
    'ConditionExpression' => 'attribute_not_exists(#h)',
    'ExpressionAttributeNames' => array('#h' => 'hash')
));
0
ioioio