Open9

Amplify Studio - DataStoreによるシンプルなデータアクセス方法

N2LabN2Lab

Ampify Studio で collection ui component を開発すると、自動的にDBからfetchしてくれている。
そのソースをたどるとDataStore APIで取得しているとのこと。
内部的にはGraphQL APIだが、DataStore APIを利用したほうが楽そうなので使い方をまとめる。

参考

API
https://aws-amplify.github.io/amplify-js/api/classes/datastore.html
https://aws.amazon.com/jp/blogs/news/amplify-datastore-simplify-development-of-offline-apps-with-graphql/
https://docs.amplify.aws/lib/datastore/examples/q/platform/js/

前提

Contest modelをAmplify Studioで登録済

注意点

オフライン時でも一定動作し、後で同期可能
WEBアプリであればオフライン時はすぐエラーにすべきか?アプリによるかもしれない

N2LabN2Lab

全件取得

  const query = async () => {
    const contests = await DataStore.query(Contest);
  };

ID指定取得

  const query = async () => {
    const contest = await DataStore.query(
      Contest,
      "3e292085-4769-4867-981a-0efadb0ff5f4"
    );
  };

取得結果

{
    "id": "3e292085-4769-4867-981a-0efadb0ff5f4",
    "title": "abアセアンフォトコンテスト 2023",
    "intro": "アセアン諸国の魅力的な場面を撮影した写真を募集します。撮影時期は問いません。これまでにアセアン諸国を訪ねた時のお気に入りの写真やとっておきの写真をご応募ください。 自宅等で作ったアセアン料理など、日本国内で撮影したアセアンを感じることができる写真も応募できます。 応募作品の中から入賞作品を含む50点程度を2023年10月17日から30日まで、堺市役所 高層館 1階 エントランスホールにて展示します。",
    "host": "堺・アセアン交流促進委員会",
    "postStart": "2023-07-01",
    "postEnd": "2023-08-04",
    "prize": "●最優秀賞(1点) 堺ゆかりの品(刃物、お香、和晒し製品、ジャム等〈総額3万円相当〉)、賞状 ●優秀賞(2点) 堺ゆかりの品(ペティナイフ、和晒し製品、ジャム等〈総額1万円相当〉)、賞状 ●優良賞(7点) 堺ゆかりの品(爪切り、お香、ジャム等〈総額3000円相当〉)、賞状 ※賞の内容は変更の場合あり",
    "howToPost": "公式ホームページの応募フォームより ※「堺市電子申請システム」への利用者登録が必要",
    "howToPublish": null,
    "attention": null,
    "note": null,
    "deleteFlg": false,
    "createdAt": "2023-08-03T00:30:35.453Z",
    "updatedAt": "2023-08-03T01:03:39.958Z",
    "_version": 3,
    "_lastChangedAt": 1691024620000,
    "_deleted": null
}
N2LabN2Lab

検索結果のcollectionへの反映例

  return (
    <Collection
      type="list"
      direction="column"
      justifyContent="left"
      items={items || []}
      {...getOverrideProps(overrides, "ContestCard1Collection")}
      {...rest}
    >
      {(item, index) => (
        <ContestCard1
          contest={item}
          key={item.id}
          {...(overrideItems && overrideItems({ item, index }))}
        ></ContestCard1>
      )}
    </Collection>
  );
N2LabN2Lab

create

  const create = async () => {
    const result = await DataStore.save(
      new Contest({
        title: `画面から作成したコンテスト ${Date.now()}`,
      })
    );
    console.log("create result", result);
  };

console log

{
    "title": "画面から作成したコンテスト 1691025307027",
    "id": "0e7f1000-e60e-40bd-9765-6efb3416c913",
    "intro": null,
    "host": null,
    "postStart": null,
    "postEnd": null,
    "prize": null,
    "howToPost": null,
    "howToPublish": null,
    "attention": null,
    "note": null,
    "deleteFlg": null,
    "createdAt": null,
    "updatedAt": null
}
N2LabN2Lab

絞り込み条件を指定してquery

  const query = async () => {
    const contestAnd = await DataStore.query(Contest, (c) =>
      c.and((c) => [c.title.contains("画面"), c.intro.eq(null)])
    );
    console.log(
      "3. filter contest c.title.contains('画面') and c.intro.eq('')",
      contestAnd
    );
  };

このときのgraphql

{
  "query": "query operation($limit: Int, $nextToken: String, $lastSync: AWSTimestamp, $filter: ModelContestFilterInput) {\n  syncContests(\n    limit: $limit\n    nextToken: $nextToken\n    lastSync: $lastSync\n    filter: $filter\n  ) {\n    items {\n      id\n      title\n      intro\n      host\n      postStart\n      postEnd\n      prize\n      howToPost\n      howToPublish\n      attention\n      note\n      deleteFlg\n      createdAt\n      updatedAt\n      _version\n      _lastChangedAt\n      _deleted\n    }\n    nextToken\n    startedAt\n  }\n}\n",
  "variables": {
    "limit": 1000,
    "nextToken": null,
    "lastSync": 1691026076859,
    "filter": null
  }
}

・差分だけ取得している
・graphql (DB)でfilterしているわけではないので注意

N2LabN2Lab

id指定1件検索

const original = await DataStore.query(Post, id);
N2LabN2Lab

update

        const saveResult = await DataStore.save(Post.copyOf(srcObject, updated => {
          Object.assign(updated, dstObject); // 全フィールドをコピーする場合
          // または
          updated.name = 'hoge' // 特定フィールドを設定する場合
        }))
N2LabN2Lab

Objectを利用して削除

const toDelete = await DataStore.query(Post, '1234567');
if (toDelete) {
  DataStore.delete(toDelete);
}
N2LabN2Lab

削除時に条件を指定

const toDelete = await DataStore.query(Post, '123');
if (toDelete) {
  DataStore.delete(toDelete, (post) => post.status.eq(PostStatus.INACTIVE));
}