[AWS SDK for JavaScript v3] @aws-sdk/util-dynamodbのmarshallOptions/unmarshallOptionsを試してみた

2023.02.08

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 Delivery部の若槻です。

AWS SDK for JavaScript v3でDynamoDB JSONと通常のJSONの間でデータ構造の変換を行いたい場合は、@aws-sdk/util-dynamodbmarshallおよびunmarshallを使うと便利です。

marshallおよびunmarshallでは、変換のされ方を変更するオプション(marshallOptions、unmarshallOptions)がいくつか用意されています。

const marshallOptions = {
  // Whether to automatically convert empty strings, blobs, and sets to `null`.
  convertEmptyValues: false, // false, by default.
  // Whether to remove undefined values while marshalling.
  removeUndefinedValues: false, // false, by default.
  // Whether to convert typeof object to map attribute.
  convertClassInstanceToMap: false, // false, by default.
};

const unmarshallOptions = {
  // Whether to return numbers as a string instead of converting them to native JavaScript numbers.
  wrapNumbers: false, // false, by default.
};

const translateConfig = { marshallOptions, unmarshallOptions };

const client = new DynamoDBClient({});
const ddbDocClient = DynamoDBDocument.from(client, translateConfig);

今回は、marshallOptionsおよびunmarshallOptionsを実際に試してみました。

試してみた

@aws-sdk/util-dynamodbをインストールします。

npm i  @aws-sdk/util-dynamodb

marshall

まずmarshallOptionsを試してみます。次のスクリプトで動作確認を行います。

import {
  DynamoDBClient,
  PutItemCommand,
  GetItemCommand,
} from '@aws-sdk/client-dynamodb';
import { marshall, marshallOptions } from '@aws-sdk/util-dynamodb';

const client = new DynamoDBClient({
  region: 'ap-northeast-1',
});

const main = async (hoge: any, fuga: any, marshallOption: marshallOptions) => {
  const item = {
    id: 'id',
    hoge: hoge,
    fuga: fuga,
  };

  await client.send(
    new PutItemCommand({
      TableName: 'sample',
      Item: marshall(item, marshallOption),
    })
  );

  const getItemOutput = await client.send(
    new GetItemCommand({ TableName: 'sample', Key: marshall({ id: 'id' }) })
  );

  console.log(JSON.stringify(getItemOutput.Item, undefined, 2));
};

convertEmptyValues

marshallOptionsのconvertEmptyValuesは、空の値をnullに変換するオプションです。

既定では無効となっています。

main('', [''], {});

{
  "hoge": {
    "S": ""
  },
  "id": {
    "S": "id"
  },
  "fuga": {
    "L": [
      {
        "S": ""
      }
    ]
  }
}

有効にすると、stringやsetの空の値がnullに変換されました。

main('', [''], { convertEmptyValues: true });

{
  "hoge": {
    "NULL": true
  },
  "id": {
    "S": "id"
  },
  "fuga": {
    "L": [
      {
        "NULL": true
      }
    ]
  }
}

removeUndefinedValues

marshallOptionsのremoveUndefinedValuesは、値がundefinedであるプロパティを削除するオプションです。

既定では無効になっており、undefinedが指定された場合はmarshallの実行がエラーとなります。

main(undefined, undefined, {});

/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/@aws-sdk/util-dynamodb/dist-cjs/convertToAttr.js:7
        throw new Error(`Pass options.removeUndefinedValues=true to remove undefined values from map/array/set.`);
              ^
Error: Pass options.removeUndefinedValues=true to remove undefined values from map/array/set.
    at convertToAttr (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/@aws-sdk/util-dynamodb/dist-cjs/convertToAttr.js:7:15)
    at /Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/@aws-sdk/util-dynamodb/dist-cjs/convertToAttr.js:118:54
    at convertToMapAttrFromEnumerableProps (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/@aws-sdk/util-dynamodb/dist-cjs/convertToAttr.js:122:7)
    at convertToAttr (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/@aws-sdk/util-dynamodb/dist-cjs/convertToAttr.js:23:16)
    at marshall (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/@aws-sdk/util-dynamodb/dist-cjs/marshall.js:6:62)
    at main (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/marshall.ts:22:21)
    at Object.<anonymous> (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/marshall.ts:33:1)
    at Module._compile (node:internal/modules/cjs/loader:1105:14)
    at Module.m._compile (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/ts-node/src/index.ts:1618:23)
    at Module._extensions..js (node:internal/modules/cjs/loader:1159:10)

有効にすると、値がundefinedであるプロパティが削除されます。

main(undefined, undefined, { removeUndefinedValues: true });

{
  "id": {
    "S": "id"
  }
}

エラーを防ぐために、値がundefinedになりうるオブジェクトをmarshallする場合は是非とも設定しておきたいオプションですね。

unmarshall

次にunmarshallOptionsを試してみます。次のスクリプトで動作確認を行います。

import { DynamoDBClient, GetItemCommand } from '@aws-sdk/client-dynamodb';
import {
  marshall,
  unmarshall,
  unmarshallOptions,
} from '@aws-sdk/util-dynamodb';

const client = new DynamoDBClient({
  region: 'ap-northeast-1',
});

const main = async (unmarshallOptions: unmarshallOptions) => {
  const getItemOutput = await client.send(
    new GetItemCommand({ TableName: 'sample', Key: marshall({ id: 'id' }) })
  );

  console.log(
    JSON.stringify(
      unmarshall(getItemOutput.Item!, unmarshallOptions),
      undefined,
      2
    )
  );
};

wrapNumbers

unmarshallOptionsのwrapNumbersは、数値型の値をJavaScriptネイティブな値ではなく文字列型に変換します。

既定では無効になっています。

main({ wrapNumbers: false });

{
  "hoge": 123,
  "fuga": 11.11,
  "id": "id"
}

有効にすると、次のような形式となります。

main({ wrapNumbers: true });

{
  "hoge": {
    "value": "123"
  },
  "fuga": {
    "value": "11.11"
  },
  "id": "id"
}

おわりに

AWS SDK for JavaScript v3で@aws-sdk/util-dynamodbのmarshallOptions/unmarshallOptionsを試してみました。

参考

以上