0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AWS: ChatGPT で DynamoDB の UpdateCommand を再学習してみる

Posted at

背景

ChatGPT を使って学習の効率化をしたい、という思い。
GPT3.0 API を使ったりとかもやってみたけれど、まずどんなもんか?をやっぱり体験しておこう、と

やりとりの流れ

timestampserver を追加する Lambda のサンプルコードちょうだい、みたいなこといったら・・

import { DynamoDB, Lambda } from 'aws-sdk';

const dynamo = new DynamoDB.DocumentClient();

exports.handler = async (event: any, context: Lambda.Context) => {
  const user = event.Records[0].dynamodb.NewImage;
  user.timestampserver = new Date().toISOString();

  const params = {
    TableName: 'user',
    Item: user
  };

  try {
    await dynamo.put(params).promise();
    return { status: 'success' };
  } catch (err) {
    return { status: 'error', error: err };
  }
};

V2 コードを返してくれた・・
V3 にしてーってお願いしても、反応してくれなかったので、
v3 ライブラリとして、 "@aws-sdk/lib-dynamodb" 使って!ってお願いしたところ

const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');

const dynamo = new DynamoDBClient({});

exports.handler = async (event) => {
  const user = event.Records[0].dynamodb.NewImage;
  user.timestampserver = new Date().toISOString();

  const params = {
    TableName: 'user',
    Item: user
  };

  try {
    await dynamo.send(new PutItemCommand(params));
    return { status: 'success' };
  } catch (err) {
    return { status: 'error', error: err };
  }
};

何故か、下層の client-dynamodb を使って返してくれた。
一応 v3 だけど、それじゃない・・
それに、Put じゃ置換になっちゃうじゃんって突っ込んだら、Update には変えてくれた

const { DynamoDBClient, UpdateCommand } = require('@aws-sdk/client-dynamodb');

const dynamo = new DynamoDBClient({});

exports.handler = async (event) => {
  const user = event.Records[0].dynamodb.NewImage;
  user.timestampserver = new Date().toISOString();

  const params = {
    TableName: 'user',
    Key: {
      id: user.id
    },
    UpdateExpression: 'SET timestampserver = :timestampserver',
    ExpressionAttributeValues: {
      ':timestampserver': user.timestampserver
    }
  };

  try {
    await dynamo.send(new UpdateCommand(params));
    return { status: 'success' };
  } catch (err) {
    return { status: 'error', error: err };
  }
};

で、lib 使うっていいながら、lib 使ってないじゃんって突っ込んだら

My apologies, you are correct. Here is a sample code using @aws-sdk/lib-dynamodb:

と謝罪してくれて出てきたのがこちら

const { DynamoDB } = require('@aws-sdk/lib-dynamodb');

const dynamo = new DynamoDB({});

exports.handler = async (event) => {
  const user = event.Records[0].dynamodb.NewImage;
  user.timestampserver = new Date().toISOString();

  const params = {
    TableName: 'user',
    Key: {
      id: user.id
    },
    UpdateExpression: 'SET timestampserver = :timestampserver',
    ExpressionAttributeValues: {
      ':timestampserver': { S: user.timestampserver }
    }
  };

  try {
    await dynamo.updateItem(params).promise();
    return { status: 'success' };
  } catch (err) {
    return { status: 'error', error: err };
  }
};

結構いい感じになってきた。
ただ、"ExpressionAttributeNames" が無いので突っ込んだら理解して修正してくれた

const { DynamoDB } = require('@aws-sdk/lib-dynamodb');

const dynamo = new DynamoDB({});

exports.handler = async (event) => {
  const user = event.Records[0].dynamodb.NewImage;
  user.timestampserver = new Date().toISOString();

  const params = {
    TableName: 'user',
    Key: {
      id: user.id
    },
    UpdateExpression: 'SET #timestampserver = :timestampserver',
    ExpressionAttributeNames: {
      '#timestampserver': 'timestampserver'
    },
    ExpressionAttributeValues: {
      ':timestampserver': { S: user.timestampserver }
    }
  };

  try {
    await dynamo.updateItem(params).promise();
    return { status: 'success' };
  } catch (err) {
    return { status: 'error', error: err };
  }
};

で、require やめてほしかったので、

can you write like es2020 module?

って言ってみたら、簡単に書き換えてくれた :laughing:

import { DynamoDB } from '@aws-sdk/lib-dynamodb';

const dynamo = new DynamoDB({});

export const handler = async (event) => {
  const user = event.Records[0].dynamodb.NewImage;
  user.timestampserver = new Date().toISOString();

  const params = {
    TableName: 'user',
    Key: {
      id: user.id
    },
    UpdateExpression: 'SET #timestampserver = :timestampserver',
    ExpressionAttributeNames: {
      '#timestampserver': 'timestampserver'
    },
    ExpressionAttributeValues: {
      ':timestampserver': { S: user.timestampserver }
    }
  };

  try {
    await dynamo.updateItem(params).promise();
    return { status: 'success' };
  } catch (err) {
    return { status: 'error', error: err };
  }
};

timestampserver の値は、event に含まれる "ApproximateCreationDateTime" を利用してほしかったのでそれを教えたところ
ああ、それね、みたいにして直してくれたのが以下

import { DynamoDB } from '@aws-sdk/lib-dynamodb';

const dynamo = new DynamoDB({});

export const handler = async (event) => {
  const user = event.Records[0].dynamodb.NewImage;
  user.timestampserver = event.Records[0].dynamodb.ApproximateCreationDateTime;

  const params = {
    TableName: 'user',
    Key: {
      id: user.id
    },
    UpdateExpression: 'SET #timestampserver = :timestampserver',
    ExpressionAttributeNames: {
      '#timestampserver': 'timestampserver'
    },
    ExpressionAttributeValues: {
      ':timestampserver': { S: user.timestampserver }
    }
  };

  try {
    await dynamo.updateItem(params).promise();
    return { status: 'success' };
  } catch (err) {
    return { status: 'error', error: err };
  }
};

ついでに、client config に "convertClassInstanceToMap" とか使ってって言ったらでてきたのが

import { DynamoDB, UpdateCommand } from '@aws-sdk/lib-dynamodb';
import { convertClassInstanceToMap } from '@aws-sdk/util-dynamodb';

class User {
  constructor(id, timestampserver) {
    this.id = id;
    this.timestampserver = timestampserver;
  }
}

export const handler = async (event) => {
  const user = event.Records[0].dynamodb.NewImage;
  user.timestampserver = event.Records[0].dynamodb.ApproximateCreationDateTime;

  const userInstance = new User(user.id, user.timestampserver);
  const marshallOptions = convertClassInstanceToMap(userInstance);

  const dynamo = new DynamoDB.DocumentClient({
    convertEmptyValues: true,
    ...marshallOptions
  });

  const params = {
    TableName: 'user',
    Key: {
      id: user.id
    },
    UpdateExpression: 'SET #timestampserver = :timestampserver',
    ExpressionAttributeNames: {
      '#timestampserver': 'timestampserver'
    },
    ExpressionAttributeValues: {
      ':timestampserver': userInstance.timestampserver
    }
  };

  try {
    await dynamo.update(params).promise();
    return { status: 'success' };
  } catch (err) {
    return { status: 'error', error: err };
  }
};

最後に event property を聞いてみたら、こんな感じで教えてくれた。
sample data とか作るのにも適してそうね・・ほんと凄い

{
  "Records": [
    {
      "eventID": "1",
      "eventName": "INSERT",
      "eventVersion": "1.0",
      "eventSource": "aws:dynamodb",
      "awsRegion": "us-west-2",
      "dynamodb": {
        "ApproximateCreationDateTime": 1593801900,
        "Keys": {
          "Id": {
            "N": "101"
          }
        },
        "NewImage": {
          "Message": {
            "S": "New item!"
          },
          "Id": {
            "N": "101"
          }
        },
        "StreamViewType": "NEW_AND_OLD_IMAGES",
        "SequenceNumber": "111",
        "SizeBytes": 26
      },
      "eventSourceARN": "arn:aws:dynamodb:us-west-2:account-id:table/ExampleTable/stream/2015-06-27T00:48:05.899"
    }
  ]
}

あとがき

なるほど、話題の AI は流石ですね。

初学者にこそめっちゃ便利ですね。
TypeScript/JavaScript すら知らなかった三か月前の自分にとってはこれだけで以下の学びがあっただろうな、と

  • require to import の書き換え
  • V2 vs V3 の比較
  • event のプロパティの把握
    • NewImage, ApproximateCreationDateTime なんかの使い方とか
  • オブジェクトなどの結合方法
  • Put/PutItem/Update などの使い方
  • LambdaHandler の例

利用制限がある以上、毎日一時間とか、調べたいことを ChatGPT と共に学んでみるのが良さそうですね。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?