DocumentClientに拡張Arrayを渡したらMapにされる件を調査してみた

AWS運用自動化サービス「Cloud Automator」

こんにちは、PE部の中村です。
今日は、とあるシステム(typescript製)の開発中にAWS SDKのある挙動にハマってしまったので、その話を備忘録として残しておきます。

起きたこと

aws-sdkにおいて、DynamoDBのDocumentClientにArrayを継承した独自クラスを渡すと、 ['hoge', 'fuga', 'piyo'] のようなList型となって欲しいところが { '0': 'hoge', '1': 'fuga', '2': 'piyo' } のようなMap型となってしまう。

検証用リポジトリ

再現の準備

まず、下記のようにArrayを継承したExtendedArrayというクラスをGenericsを使って作成します。そして、Personクラスを作成し、それをまとめるPeopleクラスを、先程のExtendedArrayから継承して作成します。

models.ts

そして、実際にDynamoDBにデータを渡していきます。今回は5パターン用意してみました。
5パターンの説明に入る前に一旦ソースコードです。

insertdata.ts

  • パターン1: Arrayを拡張したPeopleクラスをそのまま渡す
  • パターン2: Peopleクラスは使わずに、Personクラスのインスタンスを素のArrayに入れて渡す
  • パターン3: PeopleクラスにPerson[] を返す関数 this.map(item => item) を実装し、その関数の返り値を渡す
  • パターン4: PeopleクラスにPerson[] を返す関数 new Array(...this) を実装し、その関数の返り値を渡す
  • パターン5: Peopleクラスのインスタンスを 文字列化 -> オブジェクト化する関数 JSON.parse(JSON.stringify(this)) を実装し、その関数の返り値を渡す

結果

結果は以下のようになりました。

  • パターン1: Mapになってしまう
  • パターン2: Listのまま
  • パターン3: Mapになってしまう(!?)
  • パターン4: Listのまま
  • パターン5: Listのまま

README.md

パターン3がMapになってしまうのが意外でした。ログでDynamoDBに渡すオブジェクトを出力していますが、Peopleクラスの情報が保持されたままになっていますね。 this.map(item => item) とすれば素のArrayが返ると思っていたのですが、そうではなかったようです。まだまだjs力が足りません。

拡張Arrayを保持したままDynamoDBにputするにはパターン4, 5のどちらかを採用すれば良いのですが、パターン5は見た目的にアレなのでパターン4で実装を進めていこうと思います。
(もっと良い方法を知っている人がいればぜひ教えて下さい🥺)

AWS運用自動化サービス「Cloud Automator」