Home > Software engineering >  I get back an empty array from firebase 9 getDocs request
I get back an empty array from firebase 9 getDocs request

Time:04-01

I encountered a problem in my chat app.

I works when I post message doc to the messages col but then I'm trying do getDocs back and render them I get an empty array.

I looked through FB docs, and I didn't notice any mistakes on my part. I also read an article where I was advised to use the react-firebase library with useCollectionData with which I had the same result.

const [messages, loading] = useCollectionData(
        firestore.collection('messages').orderBy('createdAt')
    )

I tried different approaches but nothing seems to work.

import React, { useState, useEffect } from 'react'
import { auth, db, app } from '../../firebase.config'
import { useAuthState } from 'react-firebase-hooks/auth'
import { useCollectionData } from 'react-firebase-hooks/firestore'
import { docs, onSnapshot, query, where, addDoc, collection, serverTimestamp, orderBy, getDocs } from 'firebase/firestore'

import Message from '../Message/Message'
import Spinner from '../Spinner/Spinner'
import './chat.css'


const Chat = () => {
  const [user, loading, error] = useAuthState(auth)
  const [value, setValue] = useState('')
  const [msgs, setMsgs] = useState([])

  console.log('msgs>>>>', msgs)

  useEffect(() => {
    const fetchMsg = async () => {
      const messagesRef = collection(db, 'messages')

      const q = query(
        messagesRef,
        orderBy('timestamp', 'desc')
      )

      const querySnap = await getDocs(q)

      let listings = []

      querySnap.forEach((doc) => {
        return listings.push({
          id: doc.id,
          data: doc.data(),
        })
      })
      setMsgs(listings)
    }
    fetchMsg()
  }, [])
  

  const sendMessage = async (e) => {
    e.preventDefault();

    const docRef = await addDoc(collection(db, 'messages'), {
      uid: user.uid,
      displayName: user.displayName,
      photoURL: user.photoURL,
      text: value,
      createdAt: serverTimestamp()
    })
    console.log(docRef)

    setValue('')
  }

  if (loading) {
    return <Spinner />
  }

  return (
    <>
      <div className='ch-wind'>
        {msgs.map((msg) => (
          <Message key={msg.id} msg={msg} style={{ backgroundColor: user.uid === msg.uid ? '#A32cc4' : '#a1045a' }} />
        ))}
      </div>

      <form className="ch-form" onSubmit={sendMessage}>
        <textarea
          value={value}
          className='ch-form-text'
          onChange={e => setValue(e.target.value)}
          placeholder='Enter your message here'
        />
        <button

          className='ch-form-btn'
        >
          Send
        </button>
      </form>
    </>
  )
}

export default Chat

CodePudding user response:

By using useEffect() hook, I would assume that you want to get the data realtime. Firestore has a realtime listeners that you can use. You can listen to a document with the onSnapshot() method. An initial call using the callback you provide creates a document snapshot immediately with the current contents of the single document. Then, each time the contents change, another call updates the document snapshot. See code below:

useEffect(() => {
  const messagesRef = query(collection(db, 'messages'), orderBy('timestamp', 'desc'));
  onSnapshot(messagesRef, (snapshot) => {
    // Maps the documents and sets them to the `msgs` state.
    setMsgs(snapshot.docs.map(doc => ({
      id: doc.id,
      data: doc.data()
    })))
  })
}, [])

Also, as pointed out by @CDoe, you should use the same Fieldname which you set from the addDoc method as you can see on the above code.

Then on the rendering, something like this:

{msgs.map((msg) => (
  // By setting the `doc.data()` to the object `data`, you should access it by `msg.data.<object_key>`
  <Message key={msg.id} msg={msg.data.text} style={{ backgroundColor: user.uid === msg.data.uid ? '#A32cc4' : '#a1045a' }} />
))}

I leave some comments on the code to better understand it.

For more information on realtime updates, you may check out this documentation.

CodePudding user response:

In the query, you're trying to orderBy timestamp. That's not a field you're creating in sendMessage.

When a value you're ordering by doesn't exist on the document, it won't return.

Maybe you meant to orderyBy the createdAt value.

const q = query(
  messagesRef,
  orderBy('createdAt', 'desc')
)
  • Related