はじめに
皆さん。こんにちは! DreamHanksのエルムです。
今回はAmplify & GraphQLでのデータモデル設計について説明していきます。
前回の記事は[第12回] データ操作です。
リレーショナルモデル (Relational models)
DataStoreは、has one、has many、 belongs toなど、モデル間の関係を扱う機能を持っています。GraphQLでは、「@connection」と「@key」というディレクティブを使用して、これを行います。
DataStoreで@keyディレクティブを使用する場合、名前を指定していれば、どんな値でもフィールドに使用することができます。ただし、nameプロパティが省略された場合、fields配列の最初の項目は “id “でなければなりません。例:@key(fields: [“id”, “content”])。
スキーマを更新する方法 (Updated schema)
以下のDataStoreを使った例では、サンプルスキーマに新しいモデルを追加してみましょう:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
enum PostStatus { ACTIVE INACTIVE } type Post @model { id: ID! title: String! rating: Int! status: PostStatus! # 新しいフィールドに @connection comments: [Comment] @connection(keyName: "byPost", fields: ["id"]) } # 新モデル type Comment @model @key(name: "byPost", fields: ["postID", "content"]) { id: ID! postID: ID! content: String! } |
リレーショナルモデルの保存する方法 (Saving relations)
接続されたモデルを保存するには、接続したいモデルのインスタンスを作成し、そのIDをDataStore.saveに渡します:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const post = await DataStore.save( new Post({ title: "私のPostにコメント", rating: 10, status: PostStatus.ACTIVE }) ); await DataStore.save( new Comment({ content: "Amplify DataStoreが大好きです。", postID: post.id }) ); |
Queryingリレーション
1 |
const comments = (await DataStore.query(Comment)).filter(c => c.postID === "123"); |
オルタナティブ:
1 2 |
const post = await DataStore.query(Post, "123"); const comments = (await DataStore.query(Comment)).filter(c => c.postID === post.id); |
リレーショナルモデルの削除する方法 (Deleting relations)
one to manyの関係にある親オブジェクトを削除すると、子オブジェクトもDataStoreから削除され、この削除のための変異がネットワーク経由で送信されます。
例えば、次のような操作を行うと、id 123のPostとそれに関連するコメントが削除されます:
1 2 |
const toDelete = await DataStore.query(Post, "123"); DataStore.delete(toDelete); |
しかし、many to manyの関係では、子供は削除されないので、明示的に削除する必要があります。
Many-to-many
上記の例では、one-to-manyスキーマを使用し、接続されたモデルを保存する方法を示しています。また、@connectionの例で示した関係のように、many to manyの関係を定義することもできます。
many-to-manyの関係では、関係の各側からモデルのインスタンスを保存し、@connectionで定義されたフィールドでタイプを接続して結合します。
次のようなスキーマを考えてみましょう:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
enum PostStatus { ACTIVE INACTIVE } type Post @model { id: ID! title: String! rating: Int status: PostStatus editors: [PostEditor] @connection(keyName: "byPost", fields: ["id"]) } type PostEditor @model(queries: null) @key(name: "byPost", fields: ["postID", "editorID"]) @key(name: "byEditor", fields: ["editorID", "postID"]) { id: ID! postID: ID! editorID: ID! post: Post! @connection(fields: ["postID"]) editor: User! @connection(fields: ["editorID"]) } type User @model { id: ID! username: String! posts: [PostEditor] @connection(keyName: "byEditor", fields: ["id"]) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// 最初にPOstを保存します。 const post = await DataStore.save( new Post({ title: "私の最初のPost", }) ); // 第二に、editor/userを保存します。 const editor = await DataStore.save( new User({ username: "DreamHanks", }) ); // そして、postとeditorをリンクさせるモードを保存します。 await DataStore.save( new PostEditor({ post: post, editor: editor }) ); |
これらのmany-to-manyの関係モデルは、直接クエリをかけて、関係にあるすべてのモデルを返すことができます。
1 2 |
// すべてのpost editorの関係 const results = await DataStore.query(PostEditor); |
これにより、PostとEditorのモデルインスタンスが添付されたPostEditorsの配列が返されます。
例えば、メタデータがない場合、上記の結果は次のようになります:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[ { "id": "4b66cee3-1436-4d53-910f-7cfe0d955cd8", "post": { "id": "d2a96183-938f-4469-9873-944336fb9d9d", "title": "私の最初のPost" }, "editor": { "id": "2cbfdd83-8353-4b0e-ae63-8f7d004c728f", "username": "DreamHanks" } } ] |
このモデル・インスタンスには、両方の関連モデルが含まれています。filter()やmap()を使って、関連するモデルのインスタンスを取得します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 指定されたエディタの全Post const postsByEditor = (await DataStore.query(PostEditor)).filter( pe => pe.editor.id === editor.id ).map(pe => pe.post); // ポストのすべてのeditors const editorsByPost = (await DataStore.query(PostEditor)).filter( pe => pe.post.id === post.id ).map(pe => pe.editor); // タイトルに "Post"が含まれるpostのすべてのeditors const editorsOfFirstPosts = (await DataStore.query(PostEditor)).filter( pe => pe.post.title.includes("Post") ).map(pe => pe.editor); // タイトルが長い記事のすべてのeditors const editorsWithLongTitles = (await DataStore.query(PostEditor)).filter( pd => pe.post.title.length > 20 ).map(pe => pe.editor); |
終わりに
今回の記事は以上になります。
次回は[第14回] データをクラウドに同期する簡単な方法を学びましょう。
ご覧いただきありがとうございます。
コメント