29

私のdbスキームでは、自動インクリメントの主キーが必要です。この機能をどのように実現できますか?

PS DynamoDBにアクセスするには、Node.jsのモジュールであるdynodeを使用します。

4

10 に答える 10

27

免責事項:私はDynamodb-mapperプロジェクトのメンテナーです

自動インクリメントキーの直感的なワークフロー:

  1. 最後のカウンター位置を取得します
  2. 1を追加
  3. オブジェクトのインデックスとして新しい番号を使用します
  4. 新しいカウンター値を保存する
  5. オブジェクトを保存します

これは、根底にある考えを説明するためだけのものです。アトミックではないため、この方法は絶対に行わないでください。特定のワークロードでは、アトミックではないため、同じIDを2つ以上の異なるオブジェクトに割り当てることができます。これにより、データが失われます。

解決策は、 UpdateItemALL_NEWとともにアトミックADD操作を使用することです。

  1. IDをアトミックに生成します
  2. オブジェクトのインデックスとして新しい番号を使用します
  3. オブジェクトを保存します

最悪のシナリオでは、オブジェクトが保存される前にアプリケーションがクラッシュしますが、同じIDを2回割り当てるリスクはありません。

残っている問題が1つあります。最後のID値をどこに保存するかです。私たちが選んだのは:

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

もちろん、確実に機能するためには、データを挿入するすべてのアプリケーションがこのシステムを認識している必要があります。そうしないと、(再び)データが上書きされる可能性があります。

最後のステップは、プロセスを自動化することです。例えば:

When hash_key is 0:
    atomically_allocate_ID()
actual_save()

実装の詳細(Python、申し訳ありません)については、https://bitbucket.org/Ludia/dynamodb-mapper/src/8173d0e8b55d/dynamodb_mapper/model.py#cl-67を参照してください。

実を言うと、私の会社では本番環境では使用していません。ほとんどの場合、ユーザー、ID、トランザクション、日時などの別のキーを見つける方がよいからです。

dynamodb-mapperのドキュメントにいくつかの例を書きましたが、Node.JSに簡単に外挿できます。

ご不明な点がございましたら、お気軽にお問い合わせください。

于 2012-08-19T22:59:00.263 に答える
14

もう1つのアプローチは、主キーが衝突する可能性が非常にUUID低いため、主キーにジェネレーターを使用することです。

DynamoDBIMOでは、生成されたsの衝突よりも、可用性の高いテーブル間で主キーカウンターを統合するときにエラーが発生する可能性が高くなりますUUID

たとえば、ノードでは次のようになります。

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'

SO回答から取得。

于 2017-08-01T17:10:45.873 に答える
5

インクリメントIDのギャップに問題がなく、行が追加された順序にほぼ対応している場合は、独自のIDをロールできます。1つの主キーを使用してNextIdTableという別のテーブルを作成します(数値)、それをカウンターと呼びます。

新しいIDを生成するたびに、次のようにします。

  • NextIdTableでGetItemを実行して、Counter->curValueの現在の値を読み取ります。
  • NextIdTableでPutItemを実行して、Counterの値をcurValue + 1に設定します。これを条件付きPutItemにして、Counterの値が変更された場合に失敗するようにします。
  • その条件付きPutItemが失敗した場合、それは他の誰かがあなたと同時にこれを行っていたことを意味します。最初からやり直します。
  • 成功した場合、curValueは新しい一意のIDです。

もちろん、実際にそのIDをどこかに適用する前にプロセスがクラッシュした場合、プロセスが「リーク」し、IDのシーケンスにギャップが生じます。また、これを他のプロセスと同時に実行している場合、1人は値39を取得し、もう1人は値40を取得します。また、データテーブルに実際に適用される順序についての保証はありません。40を獲得した人は、39を獲得した人の前にそれを書くかもしれません。しかし、それはあなたに大まかな順序を与えます。

node.jsの条件付きPutItemのパラメーターについて詳しくは、こちらをご覧ください。 http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html#!AWS/DynamoDB.html。以前にCounterから値38を読み取ったことがある場合、条件付きPutItemリクエストは次のようになります。

var conditionalPutParams = {
    TableName: 'NextIdTable',
    Item: {
        Counter: {
            N: '39'
        }
    },
    Expected: {
        Counter: {
            AttributeValueList: [
                {
                    N: '38'
                }
            ],
            ComparisonOperator: 'EQ'
        }
    }
};
于 2014-06-21T21:44:40.037 に答える
5

@yadutafの回答への追加

AWSはアトミックカウンターをサポートしています。

order_id最新のorder_numberを保持する行を持つ別のテーブル()を作成します。

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

これにより、order_numberを次のようにインクリメントし1、AWSDynamoDBからのコールバックでインクリメントされた結果を取得できます。

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
    }
  });

まれに、発信者ポイントとAWSAPI間の接続に問題がある場合があることに注意してください。これにより、dynamodb行がインクリメントされますが、接続エラーが発生します。したがって、未使用の増分値が表示される場合があります。

テーブルにincrementedを使用data.Attributes.order_numberして、テーブルに挿入する{id: data.Attributes.order_number, otherfields:{}}ことができorderます。

于 2017-04-26T10:20:07.510 に答える
5

Javaでコーディングする場合、DynamoDBMapperがユーザーに代わって一意のUUIDを生成できるようになりました。

DynamoDBAutoGeneratedKey

パーティションキーまたはソートキープロパティを自動生成としてマークします。DynamoDBMapperは、これらの属性を保存するときにランダムなUUIDを生成します。自動生成されたキーとしてマークできるのは、文字列プロパティのみです。

次のようなDynamoDBAutoGeneratedKeyアノテーションを使用します

@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; } 

上記の例でわかるように、DynamoDBAutoGeneratedKeyアノテーションとDynamoDBHashKeyアノテーションの両方を同じ属性に適用して、一意のハッシュキーを生成できます。

于 2018-01-10T17:00:47.163 に答える
4

テーブルは複数のマシンに分割されているため、SQLスタイルの自動インクリメントは不可能だと思います。私はその仕事をするPHPで自分のUUIDを生成します、あなたがjavascriptで このようなものを思い付くことができると確信しています。

于 2012-07-30T21:01:13.790 に答える
2

私も同じ問題を抱えており、この目的のためだけに小さなWebサービスを作成しました。自動インクリメント機能をシミュレートするためにDynamoDBでstateful.coをどのように使用しているかを説明するこのブログ投稿を参照してください: http ://www.yegor256.com/2014/05/18/cloud-autoincrement-counters.html

基本的に、stateful.coにアトミックカウンターを登録し、RESTful APIを使用して、新しい値が必要になるたびにそれをインクリメントします。サービスは無料です。

于 2014-05-19T08:41:38.697 に答える
1

Auto Incrementは、特定のシャードをオーバーロードしながら他のシャードをアイドル状態に保つため、パフォーマンスの観点からは適切ではありません。Dynamodbにデータを保存している場合、分散も行われません。

awsRequestId実際にはV.4UUID(ランダム)のように見えます。試してみるには、以下のコードスニペットを使用してください。

exports.handler = function(event, context, callback) {
    console.log('remaining time =', context.getRemainingTimeInMillis());
    console.log('functionName =', context.functionName);
    console.log('AWSrequestID =', context.awsRequestId);
    callback(null, context.functionName);
};

これを自分で生成する場合は、https ://www.npmjs.com/package/uuidまたはUlideを使用して、 RFC-4122に基づいてさまざまなバージョンのUUIDを生成できます。

  • V1(タイムスタンプベース)
  • V3(名前空間)
  • V4(ランダム)

Go開発者の場合、GoogleのUUIDPborman、またはSatoriからこれらのパッケージを使用できます。Pbormanはパフォーマンスが優れています。詳細については、これらの記事とベンチマークを確認してください。

ユニバーサル一意識別子の仕様の詳細については、こちらをご覧ください

于 2019-05-14T05:20:36.627 に答える
0

新しいコードを作成し、次のfile.jsコードを配置します。

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,"");
}

次に、この関数を主キーIDに適用できます。UUIDを生成します。

于 2016-12-13T11:57:19.697 に答える
0

NoSQL DynamoDBを使用していて、Dynamoose ORMを使用している場合は、デフォルトの一意のIDを簡単に設定できます。これが簡単なユーザー作成の例です

// User.modal.js

const dynamoose = require("dynamoose");

const userSchema = new dynamoose.Schema(
  {
    id: {
      type: String,
      hashKey: true,
    },
    displayName: String,
    firstName: String,
    lastName: String,
  },
  { timestamps: true },
);

const User = dynamoose.model("User", userSchema);

module.exports = User;

// User.controller.js

const { v4: uuidv4 } = require("uuid");    
const User = require("./user.model");

exports.create = async (req, res) => {
  const user = new User({ id: uuidv4(), ...req.body }); // set unique id
  const [err, response] = await to(user.save());
  if (err) {
    return badRes(res, err);
  }
  return goodRes(res, reponse);
};
于 2020-07-15T19:08:31.720 に答える