Node.js (TypeScript)で26件以上のデータをDynamoDBにBatchWriteItemするときの覚書
DynamoDBのBatchWriteの仕様が思っていたのと違ったので、ちょっと工夫が必要でした。 思っていた動き 大量のデータを入れると、25件ずつ処理してくれる。26件目以降はresponse.Unprocessed […]
広告ここから
広告ここまで
目次
DynamoDBのBatchWriteの仕様が思っていたのと違ったので、ちょっと工夫が必要でした。
思っていた動き
大量のデータを入れると、25件ずつ処理してくれる。26件目以降はresponse.UnprocessedItemsに入るので、これを使って再帰的にDynamoDB.DocumentClient.batchWriteを呼び出せばいい。
実際の動き
26件以上を投入すると即座にエラーが出る。
"1 validation error detected: Value '{ExampleDB=[com.amazonaws.dynamodb.v20120810.WriteRequest@3dbb5444, 
com.amazonaws.dynamodb.v20120810.WriteRequest@d3a97945, 
com.amazonaws.dynamodb.v20120810.WriteRequest@12edfd4a, 
com.amazonaws.dynamodb.v20120810.WriteRequest@c5039f80, 
com.amazonaws.dynamodb.v20120810.WriteRequest@8cfb9fe5]}'
 at 'requestItems' failed to satisfy constraint: Map value must satisfy constraint: [Member must have length less than or equal to 25, Member must have length greater than or equal to 1]"
やるべきこと
25件ずつ分割して実行する。
// 逐次実行するためのライブラリ(自作)
import sequentialPromise from '@hideokamoto/sequential-promise'
// 配列を25件ずつに分割するヘルパー
const splitBatchWriteItems = (items: DocumentClient.WriteRequests, splitCount: number = 24): DocumentClient.WriteRequests[] => {
    const b      = items.length
    if (b < splitCount) return [items]
    const splitItems: DocumentClient.WriteRequests[] = [];
  
    for(let i = 0; i < Math.ceil(b / splitCount); i++) {
      const j = i * splitCount;
      const p = items.slice(j, j + splitCount); // i*cnt 番目から i*cnt+cnt 番目まで取得
      splitItems.push(p);                    // 取得したものを splitItems に追加
    }
    return splitItems
  }
// 25件ずつ分割してbatchWriteする関数
const batchWriteAll = async (updateProps: DocumentClient.WriteRequests): Promise<void> => {
    const splitProps = splitBatchWriteItems(updateProps)
    await sequentialPromise<DocumentClient.WriteRequest[], void>(splitProps, async (props) => {
        await this.batchWriteItems(props)
    })
}
別に逐次実行じゃなくてもいい気はしますが、データの量が増えた時にスロットリングされると怖いなと思うのでとりあえずいれてます。
実際には適当にsleepさせてずらして実行みたいなことでもいいのかもしれません。