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

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

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

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Q&A

解決済

1回答

708閲覧

Firestoreからのデータの取得方法

ituking

総合スコア80

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

0グッド

0クリップ

投稿2023/05/14 01:41

編集2023/05/18 14:17

実現したいこと

  • Flutter×Firebase開発において、データの取得ができておらず2,3時間やっても解決に至らなかったため、有識者の力をお借りして取得及び表示を実現させたい。

前提

Flutter×Firebaseでアプリを個人開発しています。
現在、コメント機能を実装中なのですが、Firebaseに格納したコメントを取得及び表示ができなくて困っています。学習に使用している動画やドキュメントなどを見返したりしているのですが2,3時間やてみても解決しないため、有識者の方々にご教示していただきたいと考えています。

発生している問題・エラーメッセージ

Firebaseへの情報の格納はできているが、取得及び表示が完了していない。

該当のソースコード

comment_firestore.dart

1import 'package:chat_app/model/account.dart'; 2import 'package:chat_app/model/comment.dart'; 3import 'package:cloud_firestore/cloud_firestore.dart'; 4import 'package:flutter/foundation.dart'; 5 6class CommentFirestore { 7 static final _firestoreInstance = FirebaseFirestore.instance; 8 static final CollectionReference comments = 9 _firestoreInstance.collection('comments'); 10 11 static Future<dynamic> addComment(Comment newComment) async { 12 try { 13 final CollectionReference userComments = _firestoreInstance 14 .collection('user') 15 .doc(newComment.commentAccountId) 16 .collection('my_comments'); 17 var result = await comments.add({ 18 'content': newComment.content, 19 'comment_account_id': newComment.commentAccountId, 20 'comment_time': Timestamp.now(), 21 }); 22 userComments.doc(result.id).set({ 23 'comment_id': result.id, 24 'comment_time': Timestamp.now(), 25 }); 26 if (kDebugMode) { 27 print("Comment Completed."); 28 } 29 return true; 30 } on FirebaseException catch (e) { 31 if (kDebugMode) { 32 print("Comment Failed.$e"); 33 } 34 return false; 35 } 36 } 37 38 static Future<Map<String, Account>?> getCommentUserMap( 39 List<String> accountIds) async { 40 Map<String, Account> map = {}; 41 try { 42 await Future.forEach(accountIds, (String accountId) async { 43 var doc = await comments.doc(accountId).get(); 44 if (kDebugMode) { 45 print(doc); 46 } 47 Map<String, dynamic> data = doc.data() as Map<String, dynamic>; 48 if (kDebugMode) { 49 print(data); 50 } 51 // Account commentAccount = Account( 52 // id: accountId, 53 // name: data['name'], 54 // imagePath: data['image_path'], 55 // selfIntroduction: data['self_introduction'], 56 // userId: data['user_id'], 57 // ); 58 Comment commentAccount = Comment( 59 id: accountId, 60 content: data['content'], 61 commentAccountId: data['comment_account_id'], 62 imagePath: data['image_path'], 63 commentTime: Timestamp.now(), 64 ); 65 map[accountId] = commentAccount as Account; 66 if (kDebugMode) { 67 print("Completed acquisition of comment user information."); 68 } 69 return map; 70 }); 71 } on FirebaseException catch (e) { 72 if (kDebugMode) { 73 print("Failure to obtain comment user information. $e"); 74 } 75 return null; 76 } 77 return null; 78 } 79} 80 81 82 83

試したこと

Firebaseに格納されている情報を取得できない際に動画を見返して、どこが違うかを確認。
それでもわからなかったので、以下のページを参照したが解決できず。何か見落としがあり、実装できていない処理が存在するか、フィールド名が間違っているなどの可能性も考慮して見直しました。取得情報を表示する処理のファイルはコメント欄に記載します。

補足情報(FW/ツールのバージョンなど)

[✓] Flutter (Channel stable, 3.7.8, on macOS 13.2.1 22D68 darwin-x64,
locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version
32.1.0-rc1)
[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2021.2)
[✓] VS Code (version 1.76.2)
[✓] Connected device (3 available)
[✓] HTTP Host Availability

学習に使用している動画
https://www.udemy.com/share/105vZm3@Pr7FSm0zfp8qAXBT07se9r69-K2d0jGBislLihUh6OSiovR-KrudePIQug9fs-7GEg==/

ググってヒットしたページ
https://zenn.dev/tsuruo/articles/a3d77c4854e108
https://firebase.google.com/docs/firestore/query-data/get-data?hl=ja
https://tech.fundasta.co.jp/2022/01/11/y_suzuki/654

###追記
以下のページを見ながら、新たにメソッドを追加
https://www.udemy.com/course/flutter-firebase-chat/learn/lecture/33208636?start=210#overview

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

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

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

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

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

ituking

2023/05/14 01:41

```post_comment_page.dart import 'package:chat_app/firestore/comment_firestore.dart'; import 'package:chat_app/model/account.dart'; import 'package:chat_app/model/comment.dart'; import 'package:chat_app/utils/authentication.dart'; import 'package:chat_app/utils/widget_utils.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; class PostCommentPage extends StatefulWidget { const PostCommentPage({super.key}); @override State<PostCommentPage> createState() => _PostCommentPageState(); } class _PostCommentPageState extends State<PostCommentPage> { TextEditingController contentController = TextEditingController(); late final bottomSpace = MediaQuery.of(context).viewInsets.bottom; double getScreenHeight() => MediaQuery.of(context).size.height; @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: false, appBar: WidgetUtils.createAppBar("Comment"), body: SingleChildScrollView( reverse: true, child: Stack( children: [ SizedBox( height: MediaQuery.of(context).size.height - 100, child: StreamBuilder<QuerySnapshot>( stream: CommentFirestore.comments.snapshots(), builder: (context, commentSnapshot) { if (commentSnapshot.hasData) { List<String> commentAccountIds = []; for (var doc in commentSnapshot.data!.docs) { Map<String, dynamic> data = doc.data() as Map<String, dynamic>; if (!commentAccountIds .contains(data['comment_account_id'])) { commentAccountIds.add(data['comment_account_id']); } } return FutureBuilder<Map<String, Account>?>( future: CommentFirestore.getCommentUserMap( commentAccountIds), builder: (context, userSnapshot) { if (userSnapshot.hasData && userSnapshot.connectionState == ConnectionState.done) { return ListView.builder( itemCount: commentSnapshot.data!.docs.length, itemBuilder: (context, index) { Map<String, dynamic> data = commentSnapshot.data!.docs[index].data() as Map<String, dynamic>; Comment comment = Comment( id: commentSnapshot.data!.docs[index].id, content: data['content'], commentAccountId: data['comment_account_id'], commentTime: data['comment_time'], ); Account commentAccount = userSnapshot .data![comment.commentAccountId]!; return Padding( padding: const EdgeInsets.symmetric( horizontal: 15, vertical: 15), child: Row( children: [ Padding( padding: const EdgeInsets.symmetric( horizontal: 10.0), child: CircleAvatar( radius: 20, foregroundImage: NetworkImage( commentAccount.imagePath), ), ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment .spaceBetween, children: [ Row( children: [ Text( commentAccount.name, style: const TextStyle( fontWeight: FontWeight .bold), ), Text( '@${commentAccount.userId}', style: const TextStyle( color: Colors.grey, ), ), ], ), Text( DateFormat('yyyy-MM-dd-Hm') .format( comment.commentTime! .toDate(), ), ), ], ), Text(comment.content), ], ), ), ], ), ); }, ); } else { return Container(); } }); } else { return Container(); } }), ), Positioned( bottom: getScreenHeight() * 0.4, left: 0, right: 0, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 15), child: Row( children: [ Flexible( child: TextField( controller: contentController, autofocus: true, cursorColor: Colors.black, ), ), Padding( padding: const EdgeInsets.only(left: 8.0), child: IconButton( icon: const Icon(Icons.send), onPressed: () async { if (contentController.text.isNotEmpty) { Comment newComment = Comment( content: contentController.text, commentAccountId: Authentication.myAccount!.id, id: '', commentTime: null, ); var result = await CommentFirestore.addComment(newComment); if (result == true) { if (!mounted) return; Navigator.pop(context); } } }, ), ), ], ), ), ), ], ), ), ); } } ```
ituking

2023/05/16 06:42 編集

5/16 追記 ```comment_firestore.dart import 'package:chat_app/model/account.dart'; import 'package:chat_app/model/comment.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/foundation.dart'; class CommentFirestore { static final _firestoreInstance = FirebaseFirestore.instance; static final CollectionReference comments = _firestoreInstance.collection('comments'); static Future<dynamic> addComment(Comment newComment) async { try { final CollectionReference userComments = _firestoreInstance .collection('user') .doc(newComment.commentAccountId) .collection('my_comments'); var result = await comments.add({ 'content': newComment.content, 'comment_account_id': newComment.commentAccountId, 'comment_time': Timestamp.now(), }); userComments.doc(result.id).set({ 'comment_id': result.id, 'comment_time': Timestamp.now(), }); if (kDebugMode) { print("Comment Completed."); } return true; } on FirebaseException catch (e) { if (kDebugMode) { print("Comment Failed.$e"); } return false; } } static Future<Map<String, Account>?> getCommentUserMap( List<String> accountIds) async { Map<String, Account> map = {}; try { await Future.forEach(accountIds, (String accountId) async { var doc = await comments.doc(accountId).get(); Map<String, dynamic> data = doc.data() as Map<String, dynamic>; Account commentAccount = Account( id: accountId, name: data['name'], imagePath: data['image_path'], selfIntroduction: data['self_introduction'], userId: data['user_id'], ); map[accountId] = commentAccount; if (kDebugMode) { print("Completed acquisition of comment user information."); } return map; }); } on FirebaseException catch (e) { if (kDebugMode) { print("Failure to obtain comment user information. $e"); } return null; } return null; } static Future<void> fetchComments() async { try { final QuerySnapshot snapshot = await comments.get(); for (var doc in snapshot.docs) { if (kDebugMode) { print( "Successful acquisition of comment information. ${doc.id} ----- NAME: ${(doc.data() as Map<String, dynamic>)['name']}"); } } } catch (e, stackTrace) { if (kDebugMode) { print("Failure to obtain comment information. $e"); print(stackTrace); // スタックトレースを出力することでエラーの詳細を確認できます } } } } ```
ituking

2023/05/17 16:44

5/18 追記 ```post_comment_page.dart import 'package:chat_app/firestore/comment_firestore.dart'; import 'package:chat_app/model/account.dart'; import 'package:chat_app/model/comment.dart'; import 'package:chat_app/utils/authentication.dart'; import 'package:chat_app/utils/widget_utils.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; class PostCommentPage extends StatefulWidget { const PostCommentPage({super.key}); @override State<PostCommentPage> createState() => _PostCommentPageState(); } class _PostCommentPageState extends State<PostCommentPage> { TextEditingController contentController = TextEditingController(); late final bottomSpace = MediaQuery.of(context).viewInsets.bottom; double getScreenHeight() => MediaQuery.of(context).size.height; @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: false, appBar: WidgetUtils.createAppBar("Comment"), body: SingleChildScrollView( reverse: true, child: Stack( children: [ SizedBox( height: MediaQuery.of(context).size.height - 100, child: StreamBuilder<QuerySnapshot>( stream: CommentFirestore.comments.snapshots(), builder: (context, commentSnapshot) { if (commentSnapshot.hasData) { List<String> commentAccountIds = []; for (var doc in commentSnapshot.data!.docs) { Map<String, dynamic> data = doc.data() as Map<String, dynamic>; if (kDebugMode) { print("data => $data"); } if (!commentAccountIds .contains(data['comment_account_id'])) { commentAccountIds.add(data['comment_account_id']); if (kDebugMode) { print("commentAccountIds => $commentAccountIds"); } } } return FutureBuilder<Map<String, Account>?>( future: CommentFirestore.getCommentUserMap( commentAccountIds), builder: (context, userSnapshot) { if (userSnapshot.hasData && userSnapshot.connectionState == ConnectionState.done) { return ListView.builder( itemCount: commentSnapshot.data!.docs.length, itemBuilder: (context, index) { Map<String, dynamic> data = commentSnapshot.data!.docs[index].data() as Map<String, dynamic>; Comment comment = Comment( id: commentSnapshot.data!.docs[index].id, content: data['content'], commentAccountId: data['comment_account_id'], commentTime: data['comment_time'], ); Account commentAccount = userSnapshot .data![comment.commentAccountId]!; return Padding( padding: const EdgeInsets.symmetric( horizontal: 15, vertical: 15), child: Row( children: [ Padding( padding: const EdgeInsets.symmetric( horizontal: 10.0), child: CircleAvatar( radius: 20, foregroundImage: NetworkImage( commentAccount.imagePath), ), ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment .spaceBetween, children: [ Row( children: [ Text( commentAccount.name, style: const TextStyle( fontWeight: FontWeight .bold), ), Text( '@${commentAccount.userId}', style: const TextStyle( color: Colors.grey, ), ), ], ), Text( DateFormat('yyyy-MM-dd-Hm') .format( comment.commentTime! .toDate(), ), ), ], ), Text(comment.content), ], ), ), ], ), ); }, ); } else { return Container(); } }); } else { return Container(); } }), ), Positioned( bottom: getScreenHeight() * 0.4, left: 0, right: 0, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 15), child: Row( children: [ Flexible( child: TextField( controller: contentController, autofocus: true, cursorColor: Colors.black, ), ), Padding( padding: const EdgeInsets.only(left: 8.0), child: IconButton( icon: const Icon(Icons.send), onPressed: () async { if (contentController.text.isNotEmpty) { Comment newComment = Comment( content: contentController.text, commentAccountId: Authentication.myAccount!.id, id: '', commentTime: null, ); var result = await CommentFirestore.addComment(newComment); if (result == true) { if (!mounted) return; Navigator.pop(context); } } }, ), ), ], ), ), ), ], ), ), ); } } ```
ituking

2023/05/18 14:14

5/18 追記 ```post_comment_page.dart import 'package:chat_app/firestore/comment_firestore.dart'; import 'package:chat_app/model/account.dart'; import 'package:chat_app/model/comment.dart'; import 'package:chat_app/utils/authentication.dart'; import 'package:chat_app/utils/widget_utils.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; class PostCommentPage extends StatefulWidget { const PostCommentPage({super.key}); @override State<PostCommentPage> createState() => _PostCommentPageState(); } class _PostCommentPageState extends State<PostCommentPage> { TextEditingController contentController = TextEditingController(); late final bottomSpace = MediaQuery.of(context).viewInsets.bottom; double getScreenHeight() => MediaQuery.of(context).size.height; @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: false, appBar: WidgetUtils.createAppBar("Comment"), body: SingleChildScrollView( reverse: true, child: Stack( children: [ SizedBox( height: MediaQuery.of(context).size.height - 100, child: StreamBuilder<QuerySnapshot>( stream: CommentFirestore.comments.snapshots(), builder: (context, commentSnapshot) { if (commentSnapshot.hasData) { List<String> commentAccountIds = []; for (var doc in commentSnapshot.data!.docs) { Map<String, dynamic> data = doc.data() as Map<String, dynamic>; if (kDebugMode) { print("data => $data"); } if (!commentAccountIds .contains(data['comment_account_id'])) { commentAccountIds.add(data['comment_account_id']); if (kDebugMode) { print("commentAccountIds => $commentAccountIds"); } } } return FutureBuilder<Map<String, Account>?>( future: CommentFirestore.getCommentUserMap( commentAccountIds), builder: (context, userSnapshot) { if (userSnapshot.hasData && userSnapshot.connectionState == ConnectionState.done) { return ListView.builder( itemCount: commentSnapshot.data!.docs.length, itemBuilder: (context, index) { Map<String, dynamic> data = commentSnapshot.data!.docs[index].data() as Map<String, dynamic>; Comment comment = Comment( id: commentSnapshot.data!.docs[index].id, content: data['content'], commentAccountId: data['comment_account_id'], imagePath: '', commentTime: data['comment_time'], ); Account commentAccount = userSnapshot .data![comment.commentAccountId]!; return Padding( padding: const EdgeInsets.symmetric( horizontal: 15, vertical: 15), child: Row( children: [ Padding( padding: const EdgeInsets.symmetric( horizontal: 10.0), child: CircleAvatar( radius: 20, foregroundImage: NetworkImage( commentAccount.imagePath), ), ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment .spaceBetween, children: [ Row( children: [ Text( commentAccount.name, style: const TextStyle( fontWeight: FontWeight .bold), ), Text( '@${commentAccount.userId}', style: const TextStyle( color: Colors.grey, ), ), ], ), Text( DateFormat('yyyy-MM-dd-Hm') .format( comment.commentTime! .toDate(), ), ), ], ), Text(comment.content), ], ), ), ], ), ); }, ); } else { return Container(); } }); } else { return Container(); } }), ), Positioned( bottom: getScreenHeight() * 0.4, left: 0, right: 0, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 15), child: Row( children: [ Flexible( child: TextField( controller: contentController, autofocus: true, cursorColor: Colors.black, ), ), Padding( padding: const EdgeInsets.only(left: 8.0), child: IconButton( icon: const Icon(Icons.send), onPressed: () async { if (contentController.text.isNotEmpty) { Comment newComment = Comment( content: contentController.text, commentAccountId: Authentication.myAccount!.id, id: '', imagePath: '', commentTime: null, ); var result = await CommentFirestore.addComment(newComment); if (result == true) { if (!mounted) return; Navigator.pop(context); } } }, ), ), ], ), ), ), ], ), ), ); } } ```
guest

回答1

0

自己解決

有識者の方に教えてもらい解決。

投稿2023/05/26 01:27

ituking

総合スコア80

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.38%

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

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

質問する

関連した質問