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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

1回答

2197閲覧

Cloud FireStoreでfor文でデータを取得したい

tak88

総合スコア4

Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2020/04/05 11:06

前提・実現したいこと

目的はjavascriptでユーザー名をfirestoreから取得することです。
ただし、ユーザー名は変更できるようにしたいため、
[users(コレクション)]→[ユーザーid(ドキュメント)]→[ユーザー名(フィールド)]
という形でデータを格納しています。(下図参照)
イメージ説明

ここで、ユーザーidによる乗客リスト(passenger_list)を作成します。そして、その要素ごとにユーザー名をfirestoreから取得したところ、正常に動作しました。

(例)乗客の数:2名

javascript

1var passenger_list =["1番目のuid", "2番目のuid"]; 2for ( var i = 0,len = passenger_list.length; i < len; i++ ) { 3 db.collection("users/").doc(passenger_list[i]).get().then(function(doc) { 4 if (doc.exists) { 5 passenger_name = doc.data().name; 6 console.log(passenger_name); 7 } 8}); 9} 10// 実行結果: 11// "1番目のusername" 12// "2番目のusername"

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

しかしながら、このプログラムをforループさせたところ、実行結果が以下のようになりました。

該当のソースコード

(例)ループ回数:2回 乗客の数:2名

javascript

1for ( var j = 0; j < 2; j++ ) {//j:ループ回数 2 var passenger_list =["1番目のuid", "2番目のuid"]; 3 for ( var i = 0,len = passenger_list.length; i < len; i++ ) { 4 db.collection("users/").doc(passenger_list[i]).get().then(function(doc) { 5 if (doc.exists) { 6 passenger_name = doc.data().name; 7 console.log(passenger_name); 8 } 9 }); 10 } 11} 12// 実行結果: 13// "1番目のusername" 14// "1番目のusername" 15// "2番目のusername" 16// "2番目のusername"

本来は
"1番目のusername"
"2番目のusername"
"1番目のusername"
"2番目のusername"
という風に動作させたいのですが、その方法が分からなかったため質問させていただきました。

試したこと

Consoleで検証したところ、if (doc.exists) {}が4回連続で実行されていました。即ち、ループ終了時にデータベースから一度にユーザー名が取得されていると考えられます。

また、jsのpromiseや、jQueryの.when.doneなども試しましたが、同様の結果となりました。(firestoreを使った途端に実行順序が変わってしまいます。)

つきましては、目標の動作を行う方法をご教授いただければ幸いです。
また、ユーザーidとユーザー名の構成をより簡潔にする方法などもありましたら教えていただきたいと思います。

当方初学者ですので、低レベルな質問だとは思いますが、よろしくお願いいたします。

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

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

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

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

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

guest

回答1

0

Promiseを使って実現できるはずですね。
提示されたコードだと、ここの部分がPromiseで、

js

1 db.collection("users/").doc(passenger_list[i]).get()

次の関数は上記のget()の結果が返り次第実行されるもので、完了を待たずに次のループを実行してしまいます。

js

1 .then(function(doc) { 2 if (doc.exists) { 3 passenger_name = doc.data().name; 4 console.log(passenger_name); 5 } 6 });

このままだとget()の結果次第で出力順が変わってしまいます、

順番通りに実行する実装の仕方はいろいろありますが、forをどうしても使いたいならasync functionを使うとか。
そうでなければPromise.all()が使えるように配列を作ればできると思います。

実行しないで書いたので間違えてるかもしれませんが、以下のような感じで書けたと思います。
async function使う方法

js

1async function hoge() { 2 for (let j = 0; j < 2; j++) {//j:ループ回数 3 const passenger_list = ["1番目のuid", "2番目のuid"]; 4 for (let i = 0, len = passenger_list.length; i < len; i++ ) { 5 const doc = await db.doc(`users/${passenger_list[i]}`).get(); // awaitなのでここで待つ 6 if (doc && doc.exists) { 7 console.log(doc.get("name")); 8 } 9 } 10 } 11} 12hoge(); //非同期処理を実行

Promise.all使う方法

js

1Promise.all(Array(2).map(() => {//2:ループ回数 2 const promises = ["1番目のuid", "2番目のuid"].map((uid) => { 3 return new Promise((resolve, reject) => { 4 db.doc(`users/${uid}`) 5 .get() 6 .then((doc) => { 7 if (doc.exists) { 8 resolve(doc.get("name")); 9 } else { 10 reject(); 11 } 12 }) 13 .catch((err) => { 14 reject(err); 15 }); 16 }); 17 }); 18 return Promise.all(promises); 19})).then((values) => { 20 // ここの結果どうなるか忘れました。。 21});

また、ユーザーidとユーザー名の構成をより簡潔にする方法などもありましたら教えていただきたいと思います。

質問に答えていて疑問だったのですが、passenger_listに持っているUIDはどこからとってきたのでしょうか。
collectionから取得しているならばその時にユーザー名も取得できる気がしました。

投稿2020/04/08 07:39

編集2020/04/08 07:44
aaharu

総合スコア441

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問