質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

AWS(Amazon Web Services)

Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

Q&A

解決済

2回答

2918閲覧

AWS AppSync(iOS Swiftを使っています)のGraphQLのQuery with Predicatesがわかりません。

daigororo

総合スコア9

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

AWS(Amazon Web Services)

Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

0グッド

1クリップ

投稿2020/04/04 11:59

私は、バックエンドをAWSを用いてiOSアプリ(Swift)の開発を行っています。
今回、この記事をご覧になる方が多くなるように、あえてこのようなタイトルにしましたが、私が困っているのはタイトルの問題ではありません。
タイトルと違い申し訳ありませんが、私が困っていることはとてもニッチなことだと思いますので、多くの目に触れれるようにさせていただきました。
もし私の困っていることの解決策をご存知の方がいらっしゃいましたら、どうかご教授願います。

前提:AWS Amplifyを用いた,iOS(Swift)アプリの開発を行っています。
GraphQLを用いたDynamoDBとのやりとりを行う際に、Relational models
https://aws-amplify.github.io/docs/ios/datastore を参考にしました。

スキーマはこのような感じです。

GraphQL

1type Post @model { 2 id: ID! 3 title: String! 4 comments: [Comment] @connection(name: "pToc") 5 rating: Int! 6 status: String! 7} 8type Comment @model { 9 id: ID! 10 content: String 11 post: Post @connection(name: "pToc") 12} 13

また、作成されるSwiftFileのModelは

Swift

1 2public struct Post: Model { 3 public let id: String 4 public var title: String 5 public var comments: List<Comment>? 6 public var rating: Int 7 public var status: String 8 9 public init(id: String = UUID().uuidString, 10 title: String, 11 comments: List<Comment>? = [], 12 rating: Int, 13 status: String) { 14 self.id = id 15 self.title = title 16 self.comments = comments 17 self.rating = rating 18 self.status = status 19 } 20} 21 22public struct Comment: Model { 23 public let id: String 24 public var content: String? 25 public var post: Post? 26 27 public init(id: String = UUID().uuidString, 28 content: String? = nil, 29 post: Post? = nil) { 30 self.id = id 31 self.content = content 32 self.post = post 33 } 34} 35

公式ドキュメントを参照し、Postが1個あるときに、Commentがn個取れる構造をしています。
Twitterと同じ構造です。
実際のコードは以下の通りです。

Swift

1let postWithComments = Post(title: "My post with comments", 2 rating: 5, 3 status: "active") 4//Post型のデータを作る。 5 6let comment = Comment(content: "Loving Amplify DataStore", post: postWithComments) 7 8/*Comment型のデータを作る。この時に、なんのPostデータと 1:n構造をとるか指定するために、Comment型の引数に 9post: postWithComments(上のPost型データ) と指定する。 10*/ 11 12Amplify.DataStore.save(postWithComments) { //まずPost型をレコード 13 switch $0 { 14 case .failure(let err): 15 print("Error adding post - (err.localizedDescription)") 16 case .success(let post): //成功した時の処理 17//Post型のレコードが成功した時に、Comment型のレコードも実行する。 18 Amplify.DataStore.save(comment) { 19 switch $0 { 20 case .success: 21 print("Comment saved!") 22 case .failure(let err): 23 print("Error adding comment - (err.localizedDescription)") 24 } 25 } 26 27 } 28}

公式ドキュメントから拝借しました。これを実行するとしっかりとデータベースにレコードされます。

レコードされたPostデータのidが 49E2817D-19BA-46DE-AE63-CA20F6D02AB8 だとすると、これをQueryする方法は

Swift

1 Amplify.DataStore.query(Post.self, byId: "49E2817D-19BA-46DE-AE63-CA20F6D02AB8"){ 2 switch $0 { 3 case .success(let result): 4 print("Posts: (result)") 5 case .failure(let err): 6 print("Error listing posts - (err.localizedDescription)") 7 } 8 } 9 10 11//また、このPostに対して新しいCommentを付け加えたい時は以下のようにします。 12 13 14Amplify.DataStore.query(Post.self, byId: "49E2817D-19BA-46DE-AE63-CA20F6D02AB8"){ 15 switch $0 { 16 case .success(let result): 17 print("Posts: (result)") 18//Queryで呼び出したいPostが呼び出せた時に、comment1のレコードを実行する。 19 20 let comment1 = Comment(content: "New Comment Saved!", post: result) 21 22 Amplify.DataStore.save(comment1) { 23 switch $0 { 24 case .success: 25 print("Comment saved, too!") 26 case .failure(let err): 27 print("Error adding comment - (err.localizedDescription)") 28 } 29 } 30 31 32 case .failure(let err): 33 print("Error listing posts - (err.localizedDescription)") 34 } 35 } 36

さて、ここまでが公式ドキュメントなどを読んで実装したソースコードですが、問題はここからです。

私が困っているのは、Post 1個に対して、Comment n個を抜き出したいのですがその方法がわかりません。

1つのPostに対して複数のCommentがあるわけですが、あるPostをQueryしてそのPostに関連するCommentを配列に保存した場合がわかりません。

Swift

1 2/* case .successの時は、変数resultはPost型です。 3Post型はCommentの配列を持ちますので、クラス変数にComment型の配列を宣言しておきます。 4Queryが成功した時に、上記の配列にPostのCommentを代入しようと思います。 5 6public struct Post: Model { 7 public let id: String 8 public var title: String 9 public var comments: List<Comment>? 10 public var rating: Int 11 public var status: String 12... 略 13} 14*/ 15 16var Com:[Comment]! 17 18Amplify.DataStore.query(Post.self, byId: "49E2817D-19BA-46DE-AE63-CA20F6D02AB8"){ 19 switch $0 { 20 case .success(let result): 21 print("Posts: (result)") 22 Com = result.comments 23 case .failure(let err): 24 print("Error listing posts - (err.localizedDescription)") 25 } 26 } 27

すると、 「Com = result.comments」 のところで
「Cannot assign value of type 'List<Comment>?' to type '[Comment]?'」
というエラーが、ビルドする前に出てしまいます。

ですので、「var Com:[Comment]」を「var Com:List<Comment>!」に変えてやってみると、

Swift

1var Com:List<Comment>! 2 3Amplify.DataStore.query(Post.self, byId: "49E2817D-19BA-46DE-AE63-CA20F6D02AB8"){ 4 switch $0 { 5 case .success(let result): 6 print("Posts: (result)") 7 Com = result.comments 8 print(Com) 9 case .failure(let err): 10 print("Error listing posts - (err.localizedDescription)") 11 } 12 }

ビルドできて、処理も実行できるのですが、「print(Com)」のデバックは、Optional(Amplify.List<daigororo.Comment>)となってしまい、要素が見えない状況です。(daigororoはアプリの名前です。)

私は、このCommentをUITableViewCellに表示したいので、なんとか要素を見えるよな配列に保存したいのですができません。もしわかる方がいらっしゃたら、ご教授お願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

daigakuse-

2020/04/04 15:17

全く関係ない内容のお話なのですが、、、、 実機でIAM認証のログインを実装しているのですが、実機のみ落ちてしまいます。 認証にIAMを用いた実装を行なった経験はございますでしょうか。 いきなりの質問で失礼かとは思いますが、お返事いただけたら幸いです。
daigororo

2020/04/04 15:42

daigakuse-さん、こんばんは。いきなりなんてとんでもございません。 AWS Amplifyを用いたiOSアプリ開発は公式ドキュメントもあまり充実していない上に、そもそも公式ドキュメント自体が間違っていることもありました笑 daigakuse-さんのおっしゃているのは、Amazon Cognitoでのログイン機能(ユーザープールへの)を、NavigationControllerとかを付けて、実装していると言うことでしょうか? また実機のみ落ちると言うのは、実機にインストールされた途端に、FatalErrorが出ると言うことですか?? お門違いなことを言っていたらすみません????
daigakuse-

2020/04/04 15:58

daigororoさん、ご丁寧かつ迅速なお返事ありがとうございます。。。 daigororoさんの仰る通り、Amazon Cognitoでのログイン機能(ユーザープールへの)を、NavigationControllerを付けて、実装しています。 しかし、下記コードを実装すると 実機のみThread 1: signal SIGABRTで落ちてしまいます。このコードを消すとクラッシュすることはないので、このコードが原因かと勝手に思っているのですが。。。 let appSyncConfig = try AWSAppSyncClientConfiguration(appSyncServiceConfig: AWSAppSyncServiceConfig(),credentialsProvider: AWSMobileClient.default(),cacheConfiguration: AWSAppSyncCacheConfiguration()) お恥ずかしながら、自分はプログラマーとしては初心者で見様見真似でAppSyncに手を出したので、なかなか解決法が見つからず苦しんでおります。
daigororo

2020/04/04 16:52

daigakuse-さんの困ってらっしゃることにつきましては、わかりました。 ただ現在実機として使える私のiPhoneがソフトウェアアップデート中で、Xcodeからビルドできない状態です。。。申し訳ありません???? ですので、明日またやってみようと思いますので、またご連絡差し上げます! 実は、僕も4ヶ月前にAWSやAWS Amplifyに触り始めた初心者大学生ですので、まだまだ全然です。 お互い頑張りましょう!!
daigororo

2020/04/05 07:49

daigakuse-さん、昨晩の話ですが、残念ながら私のアプリではクラッシュしません。 daigakuse-さんの教えてくれたソースコードですが、私は実装していません。daigakuse-さんはどちらのドキュメントを参考にして実装されたのでしょうか。
daigororo

2020/04/18 06:36

ご返信が遅くなり、大変申し訳ございません。 Wi-Fiの調子が悪かったらしく、返信できたと思っておりましたが、返信できていませんでした。 重ねてお詫び申し上げます。 私が参考にしていたのはdaigakuse-さんに送ってもらった下のリンクであります。しかし、そのリンクのソースコードなどを用いて実装していたところ、AWS側のリソースのバグのせいだと思われますが、 「Amplify.DataStore. ~~」のコードはうまく作動しませんでした。 現在、daigakuse-さんが参考にされているリンクで実装しております。 また、実機でのテストをしてみましたが私は落ちませんでした。 func initializeAppSync() { do { // You can choose the directory in which AppSync stores its persistent cache databases let cacheConfiguration = try AWSAppSyncCacheConfiguration() // Initialize the AWS AppSync configuration let appSyncConfig = try AWSAppSyncClientConfiguration(appSyncServiceConfig: AWSAppSyncServiceConfig(), userPoolsAuthProvider: { class MyCognitoUserPoolsAuthProvider : AWSCognitoUserPoolsAuthProviderAsync { func getLatestAuthToken(_ callback: @escaping (String?, Error?) -> Void) { AWSMobileClient.default().getTokens { (tokens, error) in if error != nil { callback(nil, error) } else { callback(tokens?.idToken?.tokenString, nil) } } } } return MyCognitoUserPoolsAuthProvider()}(), cacheConfiguration: cacheConfiguration) // Initialize the AWS AppSync client appSyncClient = try AWSAppSyncClient(appSyncConfig: appSyncConfig) } catch { print("Error initializing appsync client. \(error)") } } こちらの関数を、AppDelgate.swiftの中の func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { initializeAppSync() } で、呼び出してください。 その際に、 do { // You can choose the directory in which AppSync stores its persistent cache databases let cacheConfiguration = try AWSAppSyncCacheConfiguration() // AppSync configuration & client initialization let appSyncServiceConfig = try AWSAppSyncServiceConfig() let appSyncConfig = try AWSAppSyncClientConfiguration(appSyncServiceConfig: appSyncServiceConfig, cacheConfiguration: cacheConfiguration) appSyncClient = try AWSAppSyncClient(appSyncConfig: appSyncConfig) print("Initialized appsync client.") } catch { print("Error initializing appsync client. \(error)") } このコードは消しておいてください!! そうすれば、落ちないと思います!
daigakuse-

2020/04/21 15:27 編集

お詫びだなんてとんでもないです。 クラッシュなのですが、xcodeをアップデートしたら起きなくなりました。特に原因はわからなかったです。 お手数をおかけいたしました。 もし失礼でなければ、個人での質問などさせていただきたくおもうのですがいかがでしょうか。
daigororo

2020/04/21 09:25

daigakuse-さん、ご連絡ありがとうございます。 実は私、大学生でありながらも会社を経営しておりまして、そこでiOSアプリの開発部門に所属しております。AWS Amplify はまだまだ発展途上のAWSリソースですので、我が社の保有する知識や経験などは価値があるものだと認識しております。ですので大変恐縮ながら、daigakuse-さんの個人的な質問となりますと、会社の(質問や相談も)受諾開発として請け負うこととなりますので、料金が発生する恐れがあります。 ですので、それでもよろしければ我が社のTwitterアカウントで、daigakuse-さんのアカウントにアクセスさせていただきます。 このような場でビジネスの話となりましたこと、大変申し訳ございません。 ご返答お待ちしております。
daigakuse-

2020/04/21 15:27

daigororo さん、お世話になっております。 ビジネスとして取り組まれていたのですね。 立場を弁えない申し出となってしまいましたこと、お詫び申し上げます。 料金が発生してしまうことは全く問題ありません。 しかし、私は現在、自分の経験の肥しとしてAmplifyの学習を行っております。 仰られた通りAWS Amplify はまだまだ発展途上のため、誠に勝手ながらdaigororoさんに何か教えを乞う形でご相談させていただければとの思いでした。 こちらも大変恐縮ではございますが、御社に開発をお願いする形ではなく、自分の知識がつく形で今後も精進してまりたいと思っております。 年齢が近いのにAmplifyという分野に励んでいることから、勝手に親近感を抱きたくさんのご質問をぶつけてしまったことお許しください。 今後も今までのような形でお世話になることがあるかもしれませんが、ご教授いただきますと幸いです。
guest

回答2

0

自己解決

解決しました。AWS DatsStoreは現在、DynamoDBにrelationModelをレコードすることができません。
これはAWS側のリソースのバグだと思われます。

投稿2020/04/18 06:43

daigororo

総合スコア9

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

本当ですか。実質DataStoreは使えないような状態なんですかね?
@auth, enumも使えないみたいですね。。

投稿2020/04/25 02:46

編集2020/04/25 02:49
YosukeNakayama

総合スコア80

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問