ããã¯ããªã«ãããããŠæžãããã®ïŒ
æè¿ãAmazon DynamoDBã§éãã§ããŸããããä»åã§äžåºåãã«ãããããªãšæããŸãã
ãããããããDynamoDB Streamsãããã¯è©ŠããããªããããããŸãããã
ä»åã¯ãã»ã«ã³ããªã€ã³ããã¯ã¹ãããŒãã«ããŸãã
セカンダリインデックスを使用したデータアクセス性の向上 - Amazon DynamoDB
Amazon DynamoDBã®ã»ã«ã³ããªã€ã³ããã¯ã¹
Amazon DynamoDBã䜿ã£ãããŒã¿ã®ã¢ã¯ã»ã¹ã®åºæ¬ã¯ããã©ã€ããªãŒããŒã䜿ã£ãã¢ã¯ã»ã¹ã§ãã
ãšã¯ãããããã ãã§ã¯ããŒã¿ãžå¹ççã«ã¢ã¯ã»ã¹ãããã¹ãéãããŸããã»ã«ã³ããªã€ã³ããã¯ã¹ã¯ããã©ã€ããªãŒããŒä»¥å€ã®æ¹æ³ã§
ããŒã¿ã«ã¢ã¯ã»ã¹ããæ¹æ³ãæäŸããŸãã
セカンダリインデックスを使用したデータアクセス性の向上 - Amazon DynamoDB
ã»ã«ã³ããªã€ã³ããã¯ã¹ã¯ãã²ãšã€ã®ããŒãã«ã«é¢é£ä»ããããŸãããã®æãããŒãã«ã®ããšãã€ã³ããã¯ã¹ã®ãããŒã¹ããŒãã«ããš
åŒã¶ã¿ããã§ãã
ã»ã«ã³ããªã€ã³ããã¯ã¹ãäœæããæã«ã¯ãã»ã«ã³ããªããŒïŒä»£æ¿ããŒïŒã®å®çŸ©ãšãããŒã¹ããŒãã«ããã³ããŒããå±æ§ãå®çŸ©ããŸãã
ãã®æãããŒãã«ããã€ã³ããã¯ã¹ã«å¯ŸããŠããŒã¿ãã³ããŒãããŸãã
ãããŠãããŒã¿ãååŸããéã«ã¯ãããŒãã«ã«å¯ŸããŠã¯ãšãªãŒãã¹ãã£ã³ãå®è¡ããæãšåãããã«ãã€ã³ããã¯ã¹ã«å¯ŸããŠã¯ãšãªãŒã
ã¹ãã£ã³ãå®è¡ããããšã«ãªãããã§ãã
ã»ã«ã³ããªã€ã³ããã¯ã¹ã¯ãAmazon DynamoDBã«ãã£ãŠèªåçã«ã¡ã³ããã³ã¹ãããããŒã¹ããŒãã«ã®ã¢ã€ãã ãè¿œå ãå€æŽãåé€ãããš
ã€ã³ããã¯ã¹ãæŽæ°ãããå€æŽãåæ ãããŸãã
ãããã£ãŠæžããšãã»ã«ã³ããªã€ã³ããã¯ã¹ãšããã®ã¯ãå°ãå®çŸ©ãå€ããããŒã¹ããŒãã«ã®ã³ããŒãªãã ãããªãšããæ°ãããŠããŸãã
ã»ã«ã³ããªã€ã³ããã¯ã¹ã«ã¯ã以äžã®2çš®é¡ããããŸãã
- ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹
- ããŒãã£ã·ã§ã³ããŒããã³ãœãŒãããŒãæã€ããããŒã¹ããŒãã«ãšç°ãªããã®ãã»ã«ã³ããªããŒãšããŠå®çŸ©å¯èœ
- ã»ã«ã³ããªããŒã®æ§è³ªããããã®ã€ã³ããã¯ã¹ã䜿ãã¯ãšãªãŒã¯å šããŒãã£ã·ã§ã³ãå šããŒã¿ã察象ãšããå¯èœæ§ããããããã°ããŒãã«ããšãªã
- ã€ã³ããã¯ã¹ã®ããŒã¿ã¯ãããŒã¹ããŒãã«ãšã¯å¥ã®ç¬èªã®ããŒãã£ã·ã§ã³ã«ä¿åãããã¹ã±ãŒãªã³ã°ãããŒã¹ããŒãã«ãšã¯å¥ãšãªã
- ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹
- ããŒãã£ã·ã§ã³ããŒã¯ããŒã¹ããŒãã«ãšåãã§ããœãŒãããŒãç°ãªãã€ã³ããã¯ã¹
- ã€ãŸããããŒãã£ã·ã§ã³ã®ç¯å²ãããŒã¹ããŒãã«ãšåããšãªããã¢ã¯ã»ã¹å¯èœãªç¯å²ãåçã«ãªããããããŒã«ã«ããšãªã
ä»ã«ããããªãã«éãããããŸãããããã¥ã¡ã³ãã«èšèŒãããŠããå 容ããç°¡åã«ãŸãšããŸãã
ç¹åŸŽ | ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ | ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ |
---|---|---|
ãã©ã€ããªãŒããŒå®çŸ© | ããŒãã£ã·ã§ã³ããŒã®ã¿ããŸãã¯è€åããŒïŒããŒãã£ã·ã§ã³ããŒïŒãœãŒãããŒïŒ | è€åããŒïŒããŒãã£ã·ã§ã³ããŒïŒãœãŒãããŒïŒ |
ãã©ã€ããªãŒããŒã®å±æ§ | ããŒãã£ã·ã§ã³ããŒããœãŒãããŒã®ããããæååãæ°å€ããã€ããªåã®ä»»æã®ããŒã¹ããŒãã«ã®å±æ§ãšåãå®çŸ©ãå¯èœ | ããŒãã£ã·ã§ã³ããŒã¯ããŒã¹ããŒãã«ãšåãããœãŒãããŒã¯æååãæ°å€ããã€ããªåã®ä»»æã®ããŒã¹ããŒãã«ã®å±æ§ãšåãå®çŸ©ãå¯èœ |
ããŒãã£ã·ã§ã³ããŒã®ãµã€ãºå¶é | ãªã | ããŒãã£ã·ã§ã³ããŒã®å€ããšã«ãã€ã³ããã¯ã¹ã«æå®ãããã¢ã€ãã ã®åèšãµã€ãºã10GB以äžã§ããããš |
ã€ã³ããã¯ã¹ã«å¯Ÿãããªã³ã©ã€ã³æäœ | ããŒã¹ããŒãã«ã®äœæãšåæã«ã€ã³ããã¯ã¹ãäœæã§ããåŸããã€ã³ããã¯ã¹ã®è¿œå ãåé€ãè¡ãããšãå¯èœ | ããŒã¹ããŒãã«ã®äœæãšåæã«ã€ã³ããã¯ã¹ãäœæã§ããããåŸããã€ã³ããã¯ã¹ãè¿œå ãããåé€ããããšã¯ã§ããªã |
ã¯ãšãªãŒãšããŒãã£ã·ã§ã³ | å šããŒãã£ã·ã§ã³ã§ããŒãã«å šäœã«å¯ŸããŠã¯ãšãªãŒãå®è¡å¯èœ | ããŒãã£ã·ã§ã³ããŒã§æå®ãããã²ãšã€ã®ããŒãã£ã·ã§ã³ã«å¯ŸããŠå®è¡å¯èœ |
èªã¿èŸŒã¿æŽåæ§ | çµææŽåæ§ | çµææŽåæ§ã匷ãæŽåæ§ããéžæå¯èœ |
ããããžã§ãã³ã°ãããã¹ã«ãŒãããã®æ¶è²» | èªã¿èŸŒã¿ïŒæžã蟌ã¿ãšãã«ãã€ã³ããã¯ã¹ã«ç¬èªã®ããããžã§ãã³ã°ãããã¹ã«ãŒãããããããã¯ãšãªãŒãã¹ãã£ã³ãããŒã¹ããŒãã«æžã蟌ã¿æã®ã€ã³ããã¯ã¹ã®æŽæ°ã§ãã£ãã·ãã£ãŠããããæ¶è²»ãã | èªã¿èŸŒã¿ïŒæžã蟌ã¿ãšãã«ãããŒã¹ããŒãã«ã®ãã£ãã·ãã£ãŠãããã䜿çšããã¯ãšãªãŒãã¹ãã£ã³ãããŒã¹ããŒãã«æžã蟌ã¿æã®ã€ã³ããã¯ã¹ã®æŽæ°ã§ããŒã¹ããŒãã«ã®ãã£ãã·ãã£ãŠããããæ¶è²»ãã |
ååŸã§ããå±æ§ | ã¯ãšãªãŒãŸãã¯ã¹ãã£ã³ã§ã¯ãã€ã³ããã¯ã¹ã«ã³ããŒãããå±æ§ã®ã¿ããªã¯ãšã¹ãå¯èœ | ã¯ãšãªãŒãŸãã¯ã¹ãã£ã³ã§ã¯ãã€ã³ããã¯ã¹ã«ã³ããŒãããŠããªãå±æ§ããªã¯ãšã¹ãå¯èœã§ã足ããªãå±æ§ã¯ããŒã¹ããŒãã«ããèªåçã«ååŸãã |
ããèŠãŠãããšãããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã¯ããŒã¹ããŒãã«ã«å¯ŸããŠå¥ã®ãœãŒãããŒã§ã¯ãšãªãŒãå®è¡å¯èœã«ããããã®ãã®ã
ãšèšããããªãæ°ãããŸãã
ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã¯ãããŒã¹ããŒãã«ã®ããŒå®çŸ©ãç°ãªãã¬ããªã«ãšãã£ããšããã§ããããã
ãã®ä»ã
- ã»ã«ã³ããªã€ã³ããã¯ã¹ãæã€ããŒãã«ãè€æ°äœæããå ŽåãããŒãã«ãé 次äœæããå¿
èŠããã
- äœæããããŒãã«ã
ACTIVE
ã«ãªãåã«ã»ã«ã³ããªããŒãã«ãæã€ããŒãã«ãäœæããããšãããšãLimitExceededException
ãã¹ããŒããã
- äœæããããŒãã«ã
- ã€ã³ããã¯ã¹äœææã®æå®äºé
- ã€ã³ããã¯ã¹ã®çš®é¡ïŒã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ or ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ïŒ
- ã€ã³ããã¯ã¹ã®åå
- ã€ã³ããã¯ã¹ã®ããŒå®çŸ©
- ã€ã³ããã¯ã¹ã«ã³ããŒããå±æ§
- ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®å Žåãèªã¿èŸŒã¿ïŒæžã蟌ã¿ã®ãã£ãã·ãã£ãŠããã
ãã®ä»ã«è©³ããæ å ±ãç¶ãã®ã§ããã
DynamoDB のグローバルセカンダリインデックスの使用 - Amazon DynamoDB
グローバルセカンダリインデックスの管理 - Amazon DynamoDB
インデックスキー違反の検出と修正 - Amazon DynamoDB
ローカルセカンダリインデックス - Amazon DynamoDB
ä»åã¯èª¬æãèŠãã®ã¯ãããããã«ããŠããšããããåãããŠã¿ããããªãšæããŸãã
確èªã«ã¯ãAmazon DynamoDBã®ããŒã«ã«çã䜿ããŸãã
ç°å¢
ä»åã®ç°å¢ã¯ããã¡ãã
$ aws --version aws-cli/2.4.23 Python/3.8.8 Linux/5.4.0-100-generic exe/x86_64.ubuntu.20 prompt/off $ java --version openjdk 17.0.1 2021-10-19 OpenJDK Runtime Environment (build 17.0.1+12-Ubuntu-120.04) OpenJDK 64-Bit Server VM (build 17.0.1+12-Ubuntu-120.04, mixed mode, sharing)
ããŒã«ã«çã®Amazon DynamoDBïŒDynamoDB Local ïŒã®æ å ±ã
$ grep -A 2 'Release Notes' README.txt Release Notes ----------------------------- 2022-1-10 (1.18.0)
ã€ã³ã¡ã¢ãªãŒã§èµ·åãããŠãããŸãã
$ java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -inMemory
ããŒã«ã«çã®Amazon DynamoDBã«ãAWS CLIã§ã¢ã¯ã»ã¹ããããã®ã¯ã¬ãã³ã·ã£ã«ã
$ export AWS_ACCESS_KEY_ID=fakeMyKeyId $ export AWS_SECRET_ACCESS_KEY=fakeSecretAccessKey $ export AWS_DEFAULT_REGION=ap-northeast-1
確èªã¯ãAWS SDK for JavaScriptã䜿ã£ãŠãNode.jsã§è¡ããŸãã
$ node --version v16.14.0 $ npm --version 8.3.1
ããŒãã«å®çŸ©
ä»å䜿ãããŒãã«ã§ããã2ã€äœæããããšã«ããŸããã
ããŒãã«å®çŸ©ã®ã€ã¡ãŒãžã¯ä»¥äžãšããŸããããã®æç¹ã§ã¯äœæããŸãããã»ã«ã³ããªã€ã³ããã¯ã¹ãç¹ã«ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã¯
ããŒãã«äœææã«å®çŸ©ããã®ã§ã
$ aws dynamodb create-table \ --endpoint-url http://localhost:8000 \ --table-name People \ --attribute-definitions \ AttributeName=familyId,AttributeType=N \ AttributeName=firstName,AttributeType=S \ --key-schema \ AttributeName=familyId,KeyType=HASH \ AttributeName=firstName,KeyType=RANGE \ --provisioned-throughput \ ReadCapacityUnits=10,WriteCapacityUnits=5 \ --table-class STANDARD $ aws dynamodb create-table \ --endpoint-url http://localhost:8000 \ --table-name Books \ --attribute-definitions \ AttributeName=isbn,AttributeType=S \ --key-schema \ AttributeName=isbn,KeyType=HASH \ --provisioned-throughput \ ReadCapacityUnits=10,WriteCapacityUnits=5 \ --table-class STANDARD
çæ¹ã¯ãããŒãã£ã·ã§ã³ããŒã®ã¿ã®ããŒãã«ã§ãã
ããŒã¿ã¯ããããªæãã§çšæã
test/people.json
[ { "familyId": 1, "lastName": "ãã°ç°", "firstName": "ãµã¶ãš", "age": 24 }, { "familyId": 1, "lastName": "ãã°ç°", "firstName": "ãã¹ãª", "age": 28 }, { "familyId": 1, "lastName": "磯é", "firstName": "波平", "age": 54 }, { "familyId": 1, "lastName": "磯é", "firstName": "ãã", "age": 50 }, { "familyId": 1, "lastName": "磯é", "firstName": "ã«ããª", "age": 11 }, { "familyId": 1, "lastName": "磯é", "firstName": "ã¯ã«ã¡", "age": 9 }, { "familyId": 1, "lastName": "ãã°ç°", "firstName": "ã¿ã©ãª", "age": 3 }, { "familyId": 2, "lastName": "æ³¢é", "firstName": "ããªã¹ã±", "age": 26 }, { "familyId": 2, "lastName": "æ³¢é", "firstName": "ã¿ã€ã³", "age": 22 }, { "familyId": 2, "lastName": "æ³¢é", "firstName": "ã€ã¯ã©", "age": 1 } ]
test/books.json
[ { "isbn": "978-4815607654", "title": "AWSã³ã³ããèšèšã»æ§ç¯[æ¬æ Œ]å ¥é", "price": 3300, "publicationDate": "2021-10-21" }, { "isbn": "978-4295006657", "title": "Amazon Web Servicesã€ã³ãã©ãµãŒãã¹æŽ»çšå€§å š ã·ã¹ãã æ§ç¯/èªååãããŒã¿ã¹ãã¢ãé«ä¿¡é Œå (impress top gear)", "price": 5060, "publicationDate": "2019-09-05" }, { "isbn": "978-4797392579", "title": "Amazon Web Services ãã¿ãŒã³å¥æ§ç¯ã»éçšã¬ã€ã æ¹èšç¬¬2ç", "price": 3740, "publicationDate": "2018-03-23" }, { "isbn": "978-4797392562", "title": "Amazon Web Services æ¥åã·ã¹ãã èšèšã»ç§»è¡ã¬ã€ã", "price": 3520, "publicationDate": "2018-01-20" }, { "isbn": "978-4774176734", "title": "Amazon Web Serviceså®è·µå ¥é (WEB+DB PRESS plus)", "price": 2838, "publicationDate": "2015-11-10" }, { "isbn": "978-4822277376", "title": "Amazon Web Services ã¯ã©ãŠããã¶ã€ã³ãã¿ãŒã³èšèšã¬ã€ããæ¹èšç", "price": 2970, "publicationDate": "2015-05-28" }, { "isbn": "978-4822277369", "title": "Amazon Web Services ã¯ã©ãŠããã¶ã€ã³ãã¿ãŒã³å®è£ ã¬ã€ããæ¹èšç", "price": 4180, "publicationDate": "2015-03-09" } ]
ã»ã«ã³ããªã€ã³ããã¯ã¹ãäœæãã
ã§ã¯ãã»ã«ã³ããªã€ã³ããã¯ã¹ãäœæããŠã¿ãŸãããã
ãã¡ããèŠãªããäœæããŠãããŸãã
グローバルセカンダリインデックスの操作: AWS CLI - Amazon DynamoDB
ローカルセカンダリインデックスの操作: AWS CLI - Amazon DynamoDB
䜿çšããããŒãã«ãšãã©ã€ããªãŒããŒã®å®çŸ©ã¯ä»¥äžã§ããã
- PeopleããŒã㫠⊠ããŒãã£ã·ã§ã³ããŒïŒ
familyId
ïŒãšãœãŒãããŒïŒfirstName
ïŒã®è€åãã©ã€ããªãŒã㌠- BookããŒã㫠⊠ããŒãã£ã·ã§ã³ããŒïŒ
isbn
ïŒã®åäžãã©ã€ããªãŒããŒ
æçµçã«ã¯ä»¥äžã«ãªãããã«æ§æããŸãã
- PeopleããŒãã«
- ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹
- ããŒãã£ã·ã§ã³ããŒïŒ
lastName
ïŒãšãœãŒãããŒïŒage
ïŒã®è€åãã©ã€ããªãŒã㌠- ããŒãã£ã·ã§ã³ããŒïŒ
firstName
ïŒã®åäžãã©ã€ããªãŒããŒ
- ããŒãã£ã·ã§ã³ããŒïŒ
- ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹
- ããŒãã£ã·ã§ã³ããŒïŒ
familyId
ïŒãšãœãŒãããŒïŒage
ïŒã®è€åãã©ã€ããªãŒããŒ
- ããŒãã£ã·ã§ã³ããŒïŒ
- ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹
- BookããŒãã«
- ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹
- ããŒãã£ã·ã§ã³ããŒïŒ
title
ïŒã®åäžãã©ã€ããªãŒããŒ
- ããŒãã£ã·ã§ã³ããŒïŒ
- ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹
BookããŒãã«ã¯ãããŒãã£ã·ã§ã³ããŒã®ã¿ã®ããŒãã«ãªã®ã§ãã»ã«ã³ããªã€ã³ããã¯ã¹ã¯äœæã§ããŸãããããã確èªããŠãããŸãã
ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãäœæãã
ãŸãã¯ãã°ããŒãã«ã€ã³ããã¯ã¹ã®äœæããã
グローバルセカンダリインデックスの操作: AWS CLI - Amazon DynamoDB
ããŒãã£ã·ã§ã³ããŒïŒlastName
ïŒãšãœãŒãããŒïŒage
ïŒã®è€åãã©ã€ããªãŒããŒãæã€ãã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãäœæããŠ
ã¿ãŸãã
--global-secondary-indexes
ã§ãã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®å®çŸ©ãæå®ããããã§ããå®çŸ©å
容ã¯JSONã§ã
$ aws dynamodb create-table \ --endpoint-url http://localhost:8000 \ --table-name People \ --attribute-definitions \ AttributeName=familyId,AttributeType=N \ AttributeName=firstName,AttributeType=S \ AttributeName=lastName,AttributeType=S \ AttributeName=age,AttributeType=N \ --key-schema \ AttributeName=familyId,KeyType=HASH \ AttributeName=firstName,KeyType=RANGE \ --provisioned-throughput \ ReadCapacityUnits=10,WriteCapacityUnits=5 \ --table-class STANDARD \ --global-secondary-indexes \ ' [ { "IndexName": "PeopleGlobalCompositeIndex", "KeySchema": [{"AttributeName":"lastName","KeyType":"HASH"}, {"AttributeName":"age","KeyType":"RANGE"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["firstName"] }, "ProvisionedThroughput": { "ReadCapacityUnits": 10, "WriteCapacityUnits": 5 } } ] '
æåã«æããæããããŒãã«ã®å±æ§å®çŸ©ãå¢ããŠããŸãããã»ã«ã³ããªã€ã³ããã¯ã¹ã§ããŒãšããŠæå®ããå±æ§ã¯å®çŸ©ããªããŠã¯ãªããªã
ã¿ããã§ãã
--attribute-definitions \ AttributeName=familyId,AttributeType=N \ AttributeName=firstName,AttributeType=S \ AttributeName=lastName,AttributeType=S \ AttributeName=age,AttributeType=N \
ä»åäœæããã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®å
容ã¯ãã¡ããã€ã³ããã¯ã¹ã®ååã¯PeopleGlobalCompositeIndex
ãšããŸããã
[ { "IndexName": "PeopleGlobalCompositeIndex", "KeySchema": [{"AttributeName":"lastName","KeyType":"HASH"}, {"AttributeName":"age","KeyType":"RANGE"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["firstName"] }, "ProvisionedThroughput": { "ReadCapacityUnits": 10, "WriteCapacityUnits": 5 } } ]
ãªããšãªãåé ç®ã®æå³ã¯ããããªãããªãã§ããã詳ããã¯ãã¡ããžã
DynamoDB のグローバルセカンダリインデックスの使用 - Amazon DynamoDB
グローバルセカンダリインデックスの管理 - Amazon DynamoDB
次ã¯ããã®ããŒãã«ã«ããŒãã£ã·ã§ã³ããŒïŒfirstName
ïŒã®ã¿ããã©ã€ããªãŒããŒãšããã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãè¿œå ããŠã¿ãŸãã
ã³ãã³ãã¯ä»¥äžã§ããã€ã³ããã¯ã¹ã®ååã¯PeopleGlobalSimpleIndex
ãšããŸãã
$ aws dynamodb update-table \ --endpoint-url http://localhost:8000 \ --table-name People \ --attribute-definitions \ AttributeName=firstName,AttributeType=S \ --global-secondary-index-updates \ ' [ { "Create": { "IndexName": "PeopleGlobalSimpleIndex", "KeySchema": [{"AttributeName":"firstName","KeyType":"HASH"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["lastName"] }, "ProvisionedThroughput": { "ReadCapacityUnits": 10, "WriteCapacityUnits": 5 } } } ] '
--global-secondary-index-updates
ãªãã·ã§ã³ã䜿ããã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®è¿œå ãæŽæ°ãåé€ã«åãããŠCreate
ãUpdate
ã
Delete
ã®ãããããæå®ããå¿
èŠããããŸãã
ãã®æããã€ã³ããã¯ã¹ã®ããŒã«ãªãå±æ§ã®å®çŸ©ã¯æ瀺ïŒ--attribute-definitions
ïŒãå¿
èŠãªããã§ãã
æåŸã«ãããšã®ããŒãã«ãããŒãã£ã·ã§ã³ããŒïŒisbn
ïŒã®ã¿ã®ããŒãã«ã«ãããŒãã£ã·ã§ã³ããŒïŒtitle
ïŒã®ã¿ããã©ã€ããªãŒããŒãšãã
ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãã€ããŠã¿ãŸããã€ã³ããã¯ã¹ã®ååã¯BookGlobalSimpleIndex
ãšããŸãã
$ aws dynamodb create-table \ --endpoint-url http://localhost:8000 \ --table-name Books \ --attribute-definitions \ AttributeName=isbn,AttributeType=S \ AttributeName=title,AttributeType=S \ --key-schema \ AttributeName=isbn,KeyType=HASH \ --provisioned-throughput \ ReadCapacityUnits=10,WriteCapacityUnits=5 \ --table-class STANDARD \ --global-secondary-indexes \ ' [ { "IndexName": "BookGlobalSimpleIndex", "KeySchema": [{"AttributeName":"title","KeyType":"HASH"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["price"] }, "ProvisionedThroughput": { "ReadCapacityUnits": 10, "WriteCapacityUnits": 5 } } ] '
ããã§ãã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãäœæããã³ãã³ããšãã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã¯ããŒã¹ããŒãã«ã®ãã©ã€ããªãŒããŒå®çŸ©ã«
é¢ä¿ãªãããŒãå®çŸ©ã§ããããšã確èªã§ããŸããã
次ã¯ãããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãäœæããŠã¿ãŸããããã¡ãã¯ããŒãã«äœææã«äœãããšã«ãªãããã1床ããŒãã«ãåé€ããŠ
ãããŸãã
$ aws dynamodb delete-table \ --endpoint-url http://localhost:8000 \ --table-name People $ aws dynamodb delete-table \ --endpoint-url http://localhost:8000 \ --table-name Books
ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãäœæãã
次ã¯ãããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãäœæããŸãã
ローカルセカンダリインデックスの操作: AWS CLI - Amazon DynamoDB
PeopleããŒãã«ã«å¯ŸããŠãããŒãã£ã·ã§ã³ããŒïŒfamilyId
ïŒãšãœãŒãããŒïŒage
ïŒã®è€åãã©ã€ããªãŒããŒãšãã
ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãäœæããŠã¿ãŸããã€ã³ããã¯ã¹ã®ååã¯PeopleLocalCompositeIndex
ãšããŸãã
aws dynamodb create-table \ --endpoint-url http://localhost:8000 \ --table-name People \ --attribute-definitions \ AttributeName=familyId,AttributeType=N \ AttributeName=firstName,AttributeType=S \ AttributeName=age,AttributeType=N \ --key-schema \ AttributeName=familyId,KeyType=HASH \ AttributeName=firstName,KeyType=RANGE \ --provisioned-throughput \ ReadCapacityUnits=10,WriteCapacityUnits=5 \ --table-class STANDARD \ --local-secondary-indexes \ ' [ { "IndexName": "PeopleLocalCompositeIndex", "KeySchema": [{"AttributeName":"familyId","KeyType":"HASH"}, {"AttributeName":"age","KeyType":"RANGE"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["firstName"] } } ] '
ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®å Žåãã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®ããã«ProvisionedThroughput
ã®æå®ã¯èŠããŸããã
ããããæžããŠãããšãšã©ãŒã«ãªããŸãã
åé ç®ã®æå³ã¯é°å²æ°ãããããã§ããã詳ããã¯ãã¡ããžã
ローカルセカンダリインデックス - Amazon DynamoDB
ããã§1床ããŒãã«ãåé€ããŠ
$ aws dynamodb delete-table \ --endpoint-url http://localhost:8000 \ --table-name People
ããŒãã£ã·ã§ã³ããŒãããŒã¹ããŒãã«ãšç°ãªãããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®äœæãè©Šã¿ãŠã¿ãŸãã
$ aws dynamodb create-table \ --endpoint-url http://localhost:8000 \ --table-name People \ --attribute-definitions \ AttributeName=familyId,AttributeType=N \ AttributeName=firstName,AttributeType=S \ AttributeName=age,AttributeType=N \ --key-schema \ AttributeName=familyId,KeyType=HASH \ AttributeName=firstName,KeyType=RANGE \ --provisioned-throughput \ ReadCapacityUnits=10,WriteCapacityUnits=5 \ --table-class STANDARD \ --local-secondary-indexes \ ' [ { "IndexName": "PeopleLocalCompositeIndex", "KeySchema": [{"AttributeName":"firstName","KeyType":"HASH"}, {"AttributeName":"age","KeyType":"RANGE"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["lastName"] } } ] '
ããã¯ããã¯ããšã©ãŒã«ãªããŸãã
An error occurred (ValidationException) when calling the CreateTable operation: Local Secondary indices must have the same hash key as the main table
ãšããããã§ãããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã¯ããŒã¹ããŒãã«ãšåãããŒãã£ã·ã§ã³ããŒãæã€å¿ èŠãããããšã確èªã§ããŸããã
ãšããã§ãããŒãã£ã·ã§ã³ããŒã®ã¿ã®ããŒãã«ã«å¯ŸããŠããŸã£ããåãããŒå®çŸ©ã®ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãäœãããšãããš
ã©ããªãã®ã§ãããã
$ aws dynamodb create-table \ --endpoint-url http://localhost:8000 \ --table-name Books \ --attribute-definitions \ AttributeName=isbn,AttributeType=S \ AttributeName=title,AttributeType=S \ --key-schema \ AttributeName=isbn,KeyType=HASH \ --provisioned-throughput \ ReadCapacityUnits=10,WriteCapacityUnits=5 \ --table-class STANDARD \ --local-secondary-indexes \ ' [ { "IndexName": "BookLocalSimpleIndex", "KeySchema": [{"AttributeName":"isbn","KeyType":"HASH"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["title","price"] } } ] '
ããã¯ãããŒãã£ã·ã§ã³ããŒã®æå®ã®ã¿ã§ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã¯äœæã§ããªããšãããšã©ãŒã«ãªããŸãã
An error occurred (ValidationException) when calling the CreateTable operation: Local Secondary indices are not allowed on hash tables, only hash and range tables
ãšããããã§ãããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã¯è€åãã©ã€ããªãŒããŒã§å®çŸ©ããå¿ èŠãããããšã確èªã§ããŸããã
ãŸãšããŠ
æåŸã«ããããŸã§å®çŸ©ããŠããã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãå«ããããŒãã«å®çŸ©ã«ããŠãããŸãã
PeopleããŒãã«ã
$ aws dynamodb create-table \ --endpoint-url http://localhost:8000 \ --table-name People \ --attribute-definitions \ AttributeName=familyId,AttributeType=N \ AttributeName=firstName,AttributeType=S \ AttributeName=lastName,AttributeType=S \ AttributeName=age,AttributeType=N \ --key-schema \ AttributeName=familyId,KeyType=HASH \ AttributeName=firstName,KeyType=RANGE \ --provisioned-throughput \ ReadCapacityUnits=10,WriteCapacityUnits=5 \ --table-class STANDARD \ --global-secondary-indexes \ ' [ { "IndexName": "PeopleGlobalCompositeIndex", "KeySchema": [{"AttributeName":"lastName","KeyType":"HASH"}, {"AttributeName":"age","KeyType":"RANGE"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["firstName"] }, "ProvisionedThroughput": { "ReadCapacityUnits": 10, "WriteCapacityUnits": 5 } }, { "IndexName": "PeopleGlobalSimpleIndex", "KeySchema": [{"AttributeName":"firstName","KeyType":"HASH"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["lastName"] }, "ProvisionedThroughput": { "ReadCapacityUnits": 10, "WriteCapacityUnits": 5 } } ] ' \ --local-secondary-indexes \ ' [ { "IndexName": "PeopleLocalCompositeIndex", "KeySchema": [{"AttributeName":"familyId","KeyType":"HASH"}, {"AttributeName":"age","KeyType":"RANGE"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["firstName"] } } ] '
BookããŒãã«ã
$ aws dynamodb create-table \ --endpoint-url http://localhost:8000 \ --table-name Books \ --attribute-definitions \ AttributeName=isbn,AttributeType=S \ AttributeName=title,AttributeType=S \ --key-schema \ AttributeName=isbn,KeyType=HASH \ --provisioned-throughput \ ReadCapacityUnits=10,WriteCapacityUnits=5 \ --table-class STANDARD \ --global-secondary-indexes \ ' [ { "IndexName": "BookGlobalSimpleIndex", "KeySchema": [{"AttributeName":"title","KeyType":"HASH"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["price"] }, "ProvisionedThroughput": { "ReadCapacityUnits": 10, "WriteCapacityUnits": 5 } } ] '
ãã¡ããä»åã®å®çŸ©ã«ããŸãããããã®ããŒãã«ãã»ã«ã³ããªã€ã³ããã¯ã¹ã䜿ãã¢ããªã±ãŒã·ã§ã³ãæžããŠãããŸãããã
ã¢ããªã±ãŒã·ã§ã³ã®æºå
Node.jsãããžã§ã¯ããäœæããŸãã確èªã¯ããã¹ãã³ãŒãã§è¡ãããšã«ããŸãã
$ npm init -y $ npm i -D typescript $ npm i -D -E prettier $ npm i -D jest @types/jest $ npm i -D esbuild esbuild-jest $ mkdir src test
Node.jsã®å宣èšãšAWS SDK for JavaScript v2ãã€ã³ã¹ããŒã«ã
$ npm i -D @types/node@v16 $ npmi aws-sdk
äŸåé¢ä¿ã¯ããã®ããã«ãªããŸããã
"devDependencies": { "@types/jest": "^27.4.1", "@types/node": "^16.11.26", "esbuild": "^0.14.25", "esbuild-jest": "^0.5.0", "jest": "^27.5.1", "prettier": "2.5.1", "typescript": "^4.6.2" }, "dependencies": { "aws-sdk": "^2.1087.0" }
èšå®ã¯ãã¡ãã
tsconfig.json
{ "compilerOptions": { "target": "esnext", "module": "commonjs", "lib": ["esnext"], "baseUrl": "./src", "outDir": "dist", "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "noImplicitOverride": true, "noImplicitReturns": true, "noPropertyAccessFromIndexSignature": true, "esModuleInterop": true }, "include": [ "src" ] }
tsconfig.typecheck.json
{ "extends": "./tsconfig", "compilerOptions": { "baseUrl": "./", "noEmit": true }, "include": [ "src", "test" ] }
.prettierrc.json
{ "singleQuote": true }
jest.config.js
module.exports = { testEnvironment: 'node', transform: { "^.+\\.tsx?$": "esbuild-jest" } };
ä»åã¯ãããã¥ã¡ã³ãã€ã³ã¿ãŒãã§ãŒã¹ã䜿ã£ãŠããããšã«ããŸãã
ドキュメントインターフェイス - Amazon DynamoDB
APIã¯ãã¡ãã
Class: AWS.DynamoDB.DocumentClient — AWS SDK for JavaScript
ã»ã«ã³ããªã€ã³ããã¯ã¹ã䜿ã£ãŠã¿ã
ã§ã¯ãã»ã«ã³ããªã€ã³ããã¯ã¹ã䜿ãããã°ã©ã ãäœæããŸãã
ããŒã¿ã«ãããã³ã°ããã¯ã©ã¹ãäœæã
src/person.ts
export class Person { familyId: number; lastName: string; firstName: string; age: number; constructor( familyId: number, lastName: string, firstName: string, age: number ) { this.familyId = familyId; this.lastName = lastName; this.firstName = firstName; this.age = age; } }
src/book.ts
export class Book { isbn: string; title: string; price: number; publicationDate: string; constructor( isbn: string, title: string, price: number, publicationDate: string ) { this.isbn = isbn; this.title = title; this.price = price; this.publicationDate = publicationDate; } }
ãã¹ãã³ãŒãã®import
éšåãšãDocumentClient
ã®äœæã
test/secondaryindex.test.ts
import { DocumentClient } from 'aws-sdk/clients/dynamodb'; import fs from 'fs'; import { Book } from '../src/book'; import { Person } from '../src/person'; const dynamodb = new DocumentClient({ credentials: { accessKeyId: 'fakeMyKeyId', secretAccessKey: 'fakeSecretAccessKey', }, region: 'ap-northeast-1', endpoint: 'http://localhost:8000', }); // ããã«ããã¹ããæžãïŒ
ãã¹ãããŒã¿ã®ããŒããšãåé€ãæåŸã«å ¥ããŠãããŸãã
test('load data', async () => { const people = JSON.parse( await fs.promises.readFile(`${__dirname}/people.json`, 'utf8') ) as Person[]; const books = JSON.parse( await fs.promises.readFile(`${__dirname}/books.json`, 'utf8') ) as Book[]; const params: DocumentClient.BatchWriteItemInput = { RequestItems: { People: people.map((p) => ({ PutRequest: { Item: p } })), Books: books.map((b) => ({ PutRequest: { Item: b } })), }, }; await dynamodb.batchWrite(params).promise(); }); // ããã«ããã¹ããæžãïŒ test('delete data', async () => { const people = JSON.parse( await fs.promises.readFile(`${__dirname}/people.json`, 'utf8') ) as Person[]; const books = JSON.parse( await fs.promises.readFile(`${__dirname}/books.json`, 'utf8') ) as Book[]; const params: DocumentClient.BatchWriteItemInput = { RequestItems: { People: people.map((p) => ({ DeleteRequest: { Key: { familyId: p.familyId, firstName: p.firstName }, }, })), Books: books.map((b) => ({ DeleteRequest: { Key: { isbn: b.isbn } } })), }, }; await dynamodb.batchWrite(params).promise(); });
ã»ã«ã³ããªã€ã³ããã¯ã¹ã䜿ãã«ã¯ãã¯ãšãªãŒãã¹ãã£ã³ã䜿ã£ãŠã¢ã¯ã»ã¹ããããšã«ãªããŸãããšããããã§ãéå»ã«æžãããšã³ããªãŒã
èŠè¿ããªããæžããŠãããŸãã
Amazon DynamoDBローカル版(DynamoDB Local )とDocumentClientで、クエリーを試す - CLOVER🍀
Amazon DynamoDBローカル版(DynamoDB Local )とDocumentClientで、スキャンを試す - CLOVER🍀
ã¯ãšãªãŒã§ã»ã«ã³ããªã€ã³ããã¯ã¹ã䜿ã
æåã¯ã¯ãšãªãŒããè©ŠããŠãããŸãããã
ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãããããŸãã
PeopleããŒãã«ã«äœæããã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã䜿ãäŸããã¡ãã¯è€åãã©ã€ããªãŒããŒã§ãã
test("query for people's global secondary index (composite keys)", async () => { const params: DocumentClient.QueryInput = { TableName: 'People', IndexName: 'PeopleGlobalCompositeIndex', // ã€ã³ããã¯ã¹åãæå® KeyConditionExpression: 'lastName = :lastName and age <= :age', ExpressionAttributeValues: { ':lastName': '磯é', ':age': 11, }, ScanIndexForward: false, ConsistentRead: false, // ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã§ã¯ true ã«ã§ããªãïŒããã©ã«ã falseïŒ }; const result = await dynamodb.query(params).promise(); if (result.Items) { expect(result.Count).toBe(2); const katsuo = result.Items[0] as Person; expect(katsuo.familyId).toBe(1); expect(katsuo.lastName).toBe('磯é'); expect(katsuo.firstName).toBe('ã«ããª'); expect(katsuo.age).toBe(11); const wakame = result.Items[1] as Person; expect(wakame.familyId).toBe(1); expect(wakame.lastName).toBe('磯é'); expect(wakame.firstName).toBe('ã¯ã«ã¡'); expect(wakame.age).toBe(9); } else { throw new Error('test failed'); } });
ãã€ã³ãã¯ãã€ã³ããã¯ã¹åãIndexName
ãšããŠæå®ããããšã§ãããåãããŠããŒãã«åãå¿
èŠã«ãªããŸãã
const params: DocumentClient.QueryInput = { TableName: 'People', IndexName: 'PeopleGlobalCompositeIndex', // ã€ã³ããã¯ã¹åãæå® KeyConditionExpression: 'lastName = :lastName and age <= :age', ExpressionAttributeValues: { ':lastName': '磯é', ':age': 11, }, ScanIndexForward: false, ConsistentRead: false, // ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã§ã¯ true ã«ã§ããªãïŒããã©ã«ã falseïŒ };
ãŸããã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®å Žåã¯ConsistentRead
ãtrue
ã«ãããšãšã©ãŒã«ãªããŸãã
ããã¯ãã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®ç¹åŸŽãšããŠæããããŠãã話ã§ããã
次ã¯ãããŒãã£ã·ã§ã³ããŒã®ã¿ã®ãã©ã€ããªãŒããŒã®å Žåã
test("query for people's global secondary index (simple key)", async () => { const params: DocumentClient.QueryInput = { TableName: 'People', IndexName: 'PeopleGlobalSimpleIndex', // ã€ã³ããã¯ã¹åãæå® KeyConditionExpression: 'firstName = :firstName', ExpressionAttributeValues: { ':firstName': 'ããªã¹ã±', }, ScanIndexForward: false, // ConsistentRead: false, // ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã§ã¯ true ã«ã§ããªãïŒããã©ã«ã falseïŒ }; const result = await dynamodb.query(params).promise(); if (result.Items) { expect(result.Count).toBe(1); const norisuke = result.Items[0] as Person; expect(norisuke.familyId).toBe(2); expect(norisuke.lastName).toBe('æ³¢é'); expect(norisuke.firstName).toBe('ããªã¹ã±'); expect(norisuke.age).toBeUndefined(); } else { throw new Error('test failed'); } });
ããèŠããšãundefined
ã®é
ç®ãæ··ãã£ãŠããŸãã
const norisuke = result.Items[0] as Person; expect(norisuke.familyId).toBe(2); expect(norisuke.lastName).toBe('æ³¢é'); expect(norisuke.firstName).toBe('ããªã¹ã±'); expect(norisuke.age).toBeUndefined();
ããã¯ãã€ã³ããã¯ã¹å®çŸ©ã®æã«ã³ããŒããå±æ§ã«æå®ããŠããªãã£ãããã§ãã
{ "IndexName": "PeopleGlobalSimpleIndex", "KeySchema": [{"AttributeName":"firstName","KeyType":"HASH"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["lastName"] }, "ProvisionedThroughput": { "ReadCapacityUnits": 10, "WriteCapacityUnits": 5 } }
ããã§Protection
ã«æå®ããŠããå±æ§ã¯lastName
ã®ã¿ã§ããããã©ã€ããªãŒããŒã®å±æ§ã¯åžžã«ã³ããŒãããŸããæ瀺çã«æå®ããªãã£ã
age
ã®ã¿ãä»åã³ããŒãããŠããªãããã§ãã
ãã£ãšããã³ããŒãã察象ã®å±æ§ãå¢ãããããããŒãã«ã®ãã¹ãŠã®å±æ§ãã³ããŒããããã«ããããšãã§ããã®ã§ãããã¯ããããããšãš
èšå®æ¬¡ç¬¬ã§ãã
BookããŒãã«ã®ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã«ã¢ã¯ã»ã¹ããäŸã
test("query for books's global secondary index(composite keys)", async () => { const params: DocumentClient.QueryInput = { TableName: 'Books', IndexName: 'BookGlobalSimpleIndex', KeyConditionExpression: 'title = :title', ExpressionAttributeValues: { ':title': 'AWSã³ã³ããèšèšã»æ§ç¯[æ¬æ Œ]å ¥é', }, }; const result = await dynamodb.query(params).promise(); if (result.Items) { expect(result.Count).toBe(1); const containerBook = result.Items[0] as Book; expect(containerBook.isbn).toBe('978-4815607654'); expect(containerBook.title).toBe('AWSã³ã³ããèšèšã»æ§ç¯[æ¬æ Œ]å ¥é'); expect(containerBook.price).toBe(3300); expect(containerBook.publicationDate).toBeUndefined(); } else { throw new Error('test failed'); } });
ãããŸã§ã®å
容ãšãç¹ã«å€ãã£ãããšã¯ãããŸããããã ãã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®å Žåã¯ãããŒã¹ããŒãã«ãšãŸã£ããç°ãªã
ãã©ã€ããªãŒããŒæ§æãåããããŒãã«ã®ããã«ã¯ãšãªãŒãå®è¡ã§ããããšã確èªã§ããŸãããã
ç¶ããŠãããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ãããã¯PeopleããŒãã«ã®ã¿ã§ãã
test("query for people's local secondary index (composite keys)", async () => { const params: DocumentClient.QueryInput = { TableName: 'People', IndexName: 'PeopleLocalCompositeIndex', KeyConditionExpression: 'familyId = :familyId and age < :age', ExpressionAttributeValues: { ':familyId': 2, ':age': 10, }, ProjectionExpression: 'familyId,lastName,firstName,age', }; const result = await dynamodb.query(params).promise(); if (result.Items) { expect(result.Count).toBe(1); const tarao = result.Items[0] as Person; expect(tarao.familyId).toBe(2); expect(tarao.lastName).toBe('æ³¢é'); expect(tarao.firstName).toBe('ã€ã¯ã©'); expect(tarao.age).toBe(1); } else { throw new Error('test failed'); } });
ä»åã®ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®å Žåãå®çŸ©ããããªã®ã§ãµã€ãã«ãããšlastName
ãundefined
ã«ãªããŸãã
[ { "IndexName": "PeopleLocalCompositeIndex", "KeySchema": [{"AttributeName":"familyId","KeyType":"HASH"}, {"AttributeName":"age","KeyType":"RANGE"}], "Projection":{ "ProjectionType":"INCLUDE", "NonKeyAttributes":["firstName"] } } ]
ã§ãããããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®å Žåã¯ProjectionExpression
ã«å±æ§ãæå®ããããšã§ãã³ããŒããŠããªãå±æ§ãåç
§ããããšã
ã§ããŸãããããããã§ããããšåŒã¶ããã§ãã
const params: DocumentClient.QueryInput = { TableName: 'People', IndexName: 'PeopleLocalCompositeIndex', KeyConditionExpression: 'familyId = :familyId and age < :age', ExpressionAttributeValues: { ':familyId': 2, ':age': 10, }, ProjectionExpression: 'familyId,lastName,firstName,age', };
ProjectionExpression
ãæå®ããªãå Žåã¯ãä»åã®ããŒãã«ãããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®å®çŸ©ã§ã¯lastName
ã¯undefined
ã«ãªããŸãã
ProjectionExpression
ã䜿ãããšã§ãã³ããŒå¯Ÿè±¡ã«å«ãŸããŠããªãå±æ§ããã§ããããããšãã§ããŸãããåœç¶æ§èœãšãã¬ãŒããªãã«ãªãã®ã§
é »ç¹ã«ååŸããé
ç®ã§ããã°ã³ããŒå¯Ÿè±¡ã«å ããæ¹ãè¯ãã§ãããã
ãšããã§ãã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã«å¯ŸããŠã³ããŒå¯Ÿè±¡ã«æå®ããŠããªãå±æ§ãProjectionExpression
ã«å«ãããšããšã©ãŒã«
ãªããŸãã
test("query for people's global secondary index (simple key), invalid projection", async () => { const params: DocumentClient.QueryInput = { TableName: 'People', IndexName: 'PeopleGlobalSimpleIndex', // ã€ã³ããã¯ã¹åãæå® KeyConditionExpression: 'firstName = :firstName', ExpressionAttributeValues: { ':firstName': 'ããªã¹ã±', }, ScanIndexForward: false, ProjectionExpression: 'familyId,lastName,firstName,age', }; try { await dynamodb.query(params).promise(); } catch (e) { const error = e as Error; expect(error.name).toBe('ValidationException'); expect(error.message).toBe( 'One or more parameter values were invalid: Global secondary index PeopleGlobalSimpleIndex does not project [age]' ); } });
ã¹ãã£ã³ã§ã»ã«ã³ããªã€ã³ããã¯ã¹ã䜿ã
æåŸã¯ã¹ãã£ã³ã§ãã
ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ããã
test("scan for people's global secondary index (composite keys)", async () => { const params: DocumentClient.ScanInput = { TableName: 'People', IndexName: 'PeopleGlobalCompositeIndex', FilterExpression: 'lastName = :lastName and age >= :age', ExpressionAttributeValues: { ':lastName': '磯é', ':age': 50, }, }; const result = await dynamodb.scan(params).promise(); if (result.Items) { expect(result.Count).toBe(2); const fune = result.Items[0] as Person; expect(fune.familyId).toBe(1); expect(fune.lastName).toBe('磯é'); expect(fune.firstName).toBe('ãã'); expect(fune.age).toBe(50); const namihei = result.Items[1] as Person; expect(namihei.familyId).toBe(1); expect(namihei.lastName).toBe('磯é'); expect(namihei.firstName).toBe('波平'); expect(namihei.age).toBe(54); } else { throw new Error('test failed'); } });
ãã€ã³ãã¯ãã¯ãšãªãŒã®æãšåæ§ã«IndexName
ã§ã€ã³ããã¯ã¹åãæå®ãããšããã§ããã
const params: DocumentClient.ScanInput = { TableName: 'People', IndexName: 'PeopleGlobalCompositeIndex', FilterExpression: 'lastName = :lastName and age >= :age', ExpressionAttributeValues: { ':lastName': '磯é', ':age': 50, }, };
ã°ããŒãã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®å Žåã¯ConsistentRead
ãtrue
ã«æå®ã§ããªãããšãProjectionExpression
ã«ã³ããŒå¯Ÿè±¡ã«
æå®ããŠããªãå±æ§ãæå®ã§ããªãã®ãã¯ãšãªãŒãšåãã§ãã
test("scan for people's global secondary index (simple key)", async () => { const params: DocumentClient.ScanInput = { TableName: 'People', IndexName: 'PeopleGlobalSimpleIndex', FilterExpression: 'lastName = :lastName and age >= :age', ExpressionAttributeValues: { ':lastName': '磯é', ':age': 50, }, }; const result = await dynamodb.scan(params).promise(); if (result.Items) { expect(result.Count).toBe(2); const fune = result.Items[0] as Person; expect(fune.familyId).toBe(1); expect(fune.lastName).toBe('磯é'); expect(fune.firstName).toBe('ãã'); expect(fune.age).toBeUndefined(); const namihei = result.Items[1] as Person; expect(namihei.familyId).toBe(1); expect(namihei.lastName).toBe('磯é'); expect(namihei.firstName).toBe('波平'); expect(namihei.age).toBeUndefined(); } else { throw new Error('test failed'); } });
ããŒã«ã«ã»ã«ã³ããªã€ã³ããã¯ã¹ã®å Žåã¯ãProjectionExpression
ãå©çšããããšã§ã³ããŒå¯Ÿè±¡ã«æå®ããªãå±æ§ã®å€ããã§ããã§ããã®ã
ã¯ãšãªãŒãšåãã§ããã
test("scan for people's local secondary index (composite keys)", async () => { const params: DocumentClient.ScanInput = { TableName: 'People', IndexName: 'PeopleLocalCompositeIndex', FilterExpression: 'lastName = :lastName and age >= :age', ExpressionAttributeValues: { ':lastName': '磯é', ':age': 50, }, ProjectionExpression: 'familyId,lastName,firstName,age', ConsistentRead: true, }; const result = await dynamodb.scan(params).promise(); if (result.Items) { expect(result.Count).toBe(2); const fune = result.Items[0] as Person; expect(fune.familyId).toBe(1); expect(fune.lastName).toBe('磯é'); expect(fune.firstName).toBe('ãã'); expect(fune.age).toBe(50); const namihei = result.Items[1] as Person; expect(namihei.familyId).toBe(1); expect(namihei.lastName).toBe('磯é'); expect(namihei.firstName).toBe('波平'); expect(namihei.age).toBe(54); } else { throw new Error('test failed'); } });
ã¯ãšãªãŒãèŠãåŸã ãšãããŸãç¹åŸŽçãªããšããããŸããã§ããâŠã
ãšãããããåç §ã®ã¿ã§ããã»ã«ã³ããªã€ã³ããã¯ã¹ã®é°å²æ°ã¯è¯ããšããŸãããã
ãŸãšã
ä»åã¯ã2çš®é¡ã®ã»ã«ã³ããªã€ã³ããã¯ã¹ãå®çŸ©ããŠãã¯ãšãªãŒãã¹ãã£ã³ã§å©çšãããšããããã£ãŠã¿ãŸããã
ãã£ãããšã»ã«ã³ããªã€ã³ããã¯ã¹ã®æ§è³ªã¯ããã£ãã®ã§ãä»åã¯ç®çãæãããããªããšæããŸãã
ã¡ãããšäœ¿ãããšæããšãŸã ãŸã ããããç¥ããªããŠã¯ãããªãããšããããšæãã®ã§ãããä»åã¯ããã§åºåãã§âŠã