web-dev-qa-db-fra.com

Comment créer un UUID dans DynamoDB?

Dans mon schéma de base de données, j'ai besoin d'une clé primaire auto-incrémentée. Comment je peux réaliser cette fonctionnalité? 

PS Pour accéder à DynamoDB, j’utilise le module dynode , pour Node.js. 

21
NiLL

Disclaimer: Je suis le responsable du projet Dynamodb-mapper

Flux de travail intuitif d'une clé à incrémentation automatique:

  1. obtenir le dernier contre-poste
  2. ajouter 1
  3. utiliser le nouveau numéro comme index de l'objet
  4. enregistrer la nouvelle valeur du compteur
  5. sauver l'objet

Ceci est juste pour expliquer l'idée sous-jacente. Ne le faites jamais de cette façon car ce n'est pas atomique. Sous certaines charges de travail, vous pouvez attribuer le même ID à plus de 2 objets différents, car ce n'est pas atomique. Cela entraînerait une perte de données.

La solution consiste à utiliser l'opération atomic ADD avec ALL_NEW de UpdateItem :

  1. générer de manière atomique un identifiant
  2. utiliser le nouveau numéro comme index de l'objet
  3. sauver l'objet

Dans le pire des cas, l'application se bloque avant que l'objet ne soit enregistré, mais ne risque jamais d'attribuer le même ID deux fois.

Il reste un problème: où stocker la dernière valeur d’ID? Nous avons choisi:

{
    "hash_key"=-1, #0 was judged too risky as it is the default value for integers.
    "__max_hash_key__y"=N
}

Bien sûr, pour fonctionner de manière fiable, toutes les applications qui insèrent des données DOIVENT être conscientes de ce système, sans quoi vous pourriez écraser (à nouveau) les données.

la dernière étape consiste à automatiser le processus. Par exemple: 

When hash_key is 0:
    atomically_allocate_ID()
actual_save()

Pour plus de détails sur la mise en oeuvre (Python, désolé), voir https://bitbucket.org/Ludia/dynamodb-mapper/src/8173d0e8b55d/dynamodb_mapper/model.py#cl-67

Pour vous dire la vérité, mon entreprise ne l'utilise pas en production car, la plupart du temps, il est préférable de trouver une autre clé, telle que, pour l'utilisateur, un ID, une transaction, une date/heure, ...

J'ai écrit quelques exemples dans la documentation de dynamodb-mapper et elle peut facilement être extrapolée à Node.JS

Si vous avez des questions, n'hésitez pas à demander.

19
yadutaf

Si vous avez des lacunes dans votre identifiant d'incrémentation et que vous ne les acceptez que si vous ne correspondez que grossièrement à l'ordre dans lequel les lignes ont été ajoutées, vous pouvez lancer la vôtre: numérique), appelez-le Counter.

Chaque fois que vous souhaitez générer un nouvel identifiant, vous devez procéder comme suit:

  • Effectuez un GetItem sur NextIdTable pour lire la valeur actuelle de Counter -> curValue
  • Effectuez un PutItem sur NextIdTable pour définir la valeur de Counter sur curValue + 1. Définissez-le comme PutItem conditionnel pour qu'il échoue si la valeur de Counter a été modifiée. 
  • Si ce PutItem conditionnel a échoué, cela signifie que quelqu'un d'autre l'a fait en même temps que vous. Recommencer. 
  • Si cela réussit, alors curValue est votre nouvel identifiant unique.

Bien sûr, si votre processus se bloque avant d’appliquer réellement cet ID, n’importe où, vous le "ferez" et vous aurez une lacune dans votre séquence d’ID. Et si vous faites cela simultanément avec un autre processus, l'un d'entre vous obtiendra la valeur 39 et l'un d'entre vous obtiendra la valeur 40, et rien ne garantit quel ordre ils seront réellement appliqués dans votre table de données; le gars qui en a 40 pourrait l'écrire avant celui qui en a 39. Mais ça vous donne un ordre approximatif.

Les paramètres d'un PutItem conditionnel dans node.js sont détaillés ici. http://docs.aws.Amazon.com/AWSJavaScriptSDK/latest/frames.html#!AWS/DynamoDB.html . Si vous aviez déjà lu une valeur de 38 dans Counter, votre demande PutItem conditionnelle pourrait ressembler à ceci.

var conditionalPutParams = {
    TableName: 'NextIdTable',
    Item: {
        Counter: {
            N: '39'
        }
    },
    Expected: {
        Counter: {
            AttributeValueList: [
                {
                    N: '38'
                }
            ],
            ComparisonOperator: 'EQ'
        }
    }
};
5
pisomojado

Une autre approche consiste à utiliser un générateur UUID pour les clés primaires, car il est peu probable que fortement se rencontrent. 

Messagerie Internet uniquement, il est plus probable que vous rencontriez des erreurs lors de la consolidation des compteurs de clé primaire dans les tables DynamoDB hautement disponibles que lors d’affrontements dans UUIDs générés.

Par exemple, dans le noeud:

npm install uuid

var uuid = require('uuid');

// Generate a v1 (time-based) id
uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'

// Generate a v4 (random) id
uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'

Tiré de SO répondre .

4
James

Ajout à la réponse de @ yadutaf

AWS prend en charge les compteurs atomiques .

Créez une table séparée (order_id) avec une ligne contenant le dernier numéro de commande:

+----+--------------+
| id | order_number |
+----+--------------+
|  0 |         5000 |
+----+--------------+

Cela permettra d'incrémenter order_number de 1 et d'obtenir le résultat incrémenté dans un rappel d'AWS DynamoDB:

config={
  region: 'us-east-1',
  endpoint: "http://localhost:8000"
};
const docClient = new AWS.DynamoDB.DocumentClient(config); 

let param = {
            TableName: 'order_id',
            Key: {
                "id": 0
            },
            UpdateExpression: "set order_number = order_number + :val",
            ExpressionAttributeValues:{
                ":val": 1
            },
            ReturnValues: "UPDATED_NEW"
        };


docClient.update(params, function(err, data) {
   if (err) {
                console.log("Unable to update the table. Error JSON:", JSON.stringify(err, null, 2));
   } else {
                console.log(data);
                console.log(data.Attributes.order_number); // <= here is our incremented result
    }
  });

???? Sachez que, dans certains cas, les rares peuvent être dus à des problèmes de connexion entre votre point d'appelant et l'API AWS. La ligne dynamodb sera incrémentée et vous obtiendrez une erreur de connexion. Ainsi, il pourrait apparaître des valeurs incrémentées non utilisées.

Vous pouvez utiliser data.Attributes.order_number incrémenté dans votre table, par exemple. insérer {id: data.Attributes.order_number, otherfields:{}} dans la table order.

3
Artru

Je ne crois pas qu'il soit possible de procéder à une incrémentation automatique de style SQL car les tables sont partitionnées sur plusieurs ordinateurs. Je génère mon propre UUID dans PHP qui fait le travail, je suis sûr que vous pourriez trouver quelque chose de similaire comme celui-ci en JavaScript. 

3
greg

Pour ceux qui codent en Java, DynamoDBMapper peut maintenant générer des UUID uniques en votre nom.

DynamoDBAutoGeneratedKey

Marque une clé de partition ou une propriété de clé de tri comme étant générée automatiquement . DynamoDBMapper générera un UUID aléatoire lors de la sauvegarde de ceux-ci les attributs. Seules les propriétés de chaîne peuvent être marquées comme générées automatiquement clés.

Utilisez le DynamoDBAutoGeneratedKey annotation comme ceci

@DynamoDBTable(tableName="AutoGeneratedKeysExample")
public class AutoGeneratedKeys { 
    private String id;

    @DynamoDBHashKey(attributeName = "Id")
    @DynamoDBAutoGeneratedKey
    public String getId() { return id; }
    public void setId(String id) { this.id = id; } 

Comme vous pouvez le constater dans l'exemple ci-dessus, vous pouvez appliquer les annotations DynamoDBAutoGeneratedKey et DynamoDBHashKey au même attribut afin de générer une clé de hachage unique.

3
Stu

J'ai eu le même problème et créé un petit service Web juste à cette fin. Voir ce billet de blog expliquant comment j'utilise stateful.co avec DynamoDB afin de simuler la fonctionnalité d'incrémentation automatique: http://www.yegor256.com/2014/05/18/cloud- autoincrement-counters.html

En gros, vous enregistrez un compteur atomique dans stateful.co et vous l'incrémentez chaque fois que vous avez besoin d'une nouvelle valeur, via l'API RESTful. Le service est gratuit.

2
yegor256

Créez le nouveau file.js et mettez ce code:

exports.guid = function () {
    function _p8(s) {
        var p = (Math.random().toString(16)+"000000000").substr(2,8);
        return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
    }
    return (_p8() + _p8(true) + _p8(true)+new Date().toISOString().slice(0,10)).replace(/-/g,"");
}

Ensuite, vous pouvez appliquer cette fonction à l'ID de clé primaire. Il va générer l'UUID.

0
Jivi