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

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

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

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

Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

Cloud Firestore

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

JavaScript

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

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

1543閲覧

Firestoreで配列に格納された各オブジェクトの特定のプロパティを一括で変更したい

evgenia

総合スコア28

Firebase

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

Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

Cloud Firestore

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

JavaScript

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

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2021/06/10 00:25

編集2021/06/10 00:40

前提・実現したいこと・コード

FirestoreとNext.jsでSNSを開発しており、通知一覧コンポーネントを描画した際、通知を既読状態にしたいと考えています。

通知はFirestoreで下記のように、オブジェクトの配列として格納しています。

Firestore

1users 2 - uid 3 - name: "foo" 4 - notifications: 5 0: { 6 name: "bar" // 通知を送ってきたユーザーの名前 7 isRead: false // 未読の場合false 8 } 9 1: { 10 name: "baz" 11 isRead: false 12 }

通知一覧コンポーネントを描画した際に、上記のnotificationsフィールドに格納されているすべてのオブジェクトの内、isReadfalseのオブジェクトのisReadtrueにしたいです。

通知一覧コンポーネントは下記のようになっています。

javascript

1// ↓ 通知一覧コンポーネント 2const Notifs = ({ user, setOpenNotifs }) => { 3 const notifs = user.notifications.map((notif, index) => { 4 return <li key={index}>{notif.name}から通知が来ました。</li> 5 }) 6 7 return ( 8 <ul> 9 {notifs} 10 <li> 11 <button onClick={()=> setOpenNotifs(false)}>閉じる</button> 12 </li> 13 </ul> 14 ) 15} 16 17// 通知一覧コンポーネントを開くコンポーネント 18const Header = ({ user }) => { 19 const [notifLength, setNotifLength] = useState(0) 20 const [openNotifs, setOpenNotifs] = useState(false) 21 useEffect(() => { 22 if (!user || user.notifications.length < 1) return 23 const notifs = user.notifications.filter((notif) => !notif.isRead) // 未読を取得 24 setNotifLength(notifs.length) 25 }, []) 26 27 return ( 28 <hedaer> 29 <img src="logo" /> 30 <button onClick={()=> setOpenNotifs(true)}> 31 通知 32 <span>未読の数: {notifLength > 0 && notifLength}</span> 33 </button> 34 {openNofis && <Notifs user={user} setOpenNotifs={setOpenNotifs} />} 35 </header> 36 ) 37}

試したこと

通知一覧コンポーネントNotifsで下記を実行しました。

javascript

1useEffect(() => { 2 firebase.firestore().collection("users").doc(user.uid).get().then((doc) => { 3 const notifs = doc.data().notifications; 4 notifs.forEach((notif) => { 5 if(notif.isRead) return 6 console.log(notif.isRead) 7 db.collection("users").doc(user.uid).update({ isRead: true }) 8 }) 9 }) 10}, [])

結果、isReadがtrueになりませんでした。
そのため、未読数の表示も変化が無い状態です。
Notifsを描画するたびに、コンソールにはfalseが表示されます。

コンソールにisReadが表示されるため条件分岐のミスではなく、Firestoreupdateメソッドが上手く実行できていないことが原因かと思いますが、私では原因が分かりません。

また、上記のisReadtrueにする方法は非同期処理のため、例えば通知一覧コンポーネントを開いてただちに閉じた場合は処理が途中で終わり、DBのデータと実態に不整合が発生する可能性が考えられます。

Next.jsのAPIルートかCloud functionsを使ってバックエンドでisReadを書き換えることができれば、処理が途中で終わる可能性は排除できそうですが、クライアント側の処理で問題無い方法があればご教示いただきたいです。

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

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

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

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

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

guest

回答1

0

ベストアンサー

問題点整理

質問文のコードを解釈する限り、notificationsusers/UIDのドキュメント内のフィールドとして扱っています。
(通知を表示する際にも、項目へのアクセスにuser.notificationsを使っているため)

それに対して更新処理を見ると、
db.collection("users").doc(user.uid).update({ isRead: true })
としています。
これだと、users/UIDというドキュメント内のisReadというフィールドを更新しているように見えます。

※本来やろうとしていること

js

1const before = { 2 notifications: [ 3 { 4 name: "bar", 5 isRead: false, 6 }, 7 ], 8} 9const after = { 10 notifications: [ 11 { 12 name: "bar", 13 isRead: true, // notificationsフィールドの各要素内のisReadを更新 14 }, 15 ], 16}

※実際に起きていると思われること

js

1const before = { 2 notifications: [ 3 { 4 name: "bar", 5 isRead: false, 6 }, 7 ], 8} 9const after = { 10 notifications: [ 11 { 12 name: "bar", 13 isRead: false, 14 }, 15 ], 16 isRead: true, // ドキュメント直下のisReadを更新(?) 17}

解決例

例えば、「notificationsを通知状態をtrueにした上で更新する」アプローチだと、
こんな感じの実装を一例として挙げられます。
※手元での確認まではしてないですが、その場合は考え方の参考としてもらえれば

javascript

1useEffect(() => { 2 firebase.firestore().collection("users").doc(user.uid).get().then((doc) => { 3 const notifs = doc.data().notifications; 4 // 更新済み状態のnotificationsを生成 5 notif_read = notifs.map(notif => { 6 return { 7 ...notif, 8 isRead: true, 9 }; 10 }); 11 // 更新済み状態のnotificationsで更新 12 db.collection("users").doc(user.uid).update({ notifications: notif_read }); 13 }) 14}, [])

ただし、同じタイミングで別経路からnotificationsへの要素追加があったりすると、
もしかしたら追加要素を消してしまう可能性があります。

それを可能な限り避けたい場合は、例えばnotificationsをサブコレクションにするなどの検討が必要かもしれません。

投稿2021/06/12 03:29

attakei

総合スコア2740

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

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

evgenia

2021/06/12 09:05

サブコレクションにして実装できました。ありがとうございます。仰る通り、notificationsフィールドのisReadプロパティを更新するところを、isReadフィールドの更新を行なっていたことが、問題の原因でした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問