Home > Back-end >  How to order documents in a collection in Firestore
How to order documents in a collection in Firestore

Time:09-22

I have a problem, after the version 9 update of Firebase, I cant seem to figure out how to order the documents in a collection.

Here is my code. I do not seem to understand how to implement the orderBy in the onSnapshot. Can someone please nudge me in the right direction. I have looked through the documentation but could not find a solution.

import React, { useState, useEffect } from "react";
import SignOut from "./SignOut";
import { Grid, Typography, Avatar } from "@material-ui/core";
import db from "../firebase";
import { onSnapshot, collection, orderBy, query, limit } from "firebase/firestore";
import SendMessage from "./SendMessage";

function ChatBox() {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    onSnapshot(collection(db, "messages"), (snapshot) => {
      setMessages(snapshot.docs.map((doc) => doc.data()));
    });
  }, []);
  return (
    <>
      <Grid container>
        <Grid item xs="12" style={{ textAlign: "right" }}>
          <SignOut></SignOut>
        </Grid>
        {messages.map(({ id, text, photoURL }) => (
          <Grid item xs="12" key={id} style={{ marginBottom: "1rem" }}>
            <Avatar alt="" src={photoURL} />
            <Typography>{text}</Typography>
          </Grid>
        ))}
      </Grid>
      <Grid container>
        <SendMessage></SendMessage>
      </Grid>
    </>
  );
}

export default ChatBox;

CodePudding user response:

Okay, I found a solution:

When you use the order by, if the field you are trying to order the documents by does not excist in the document, the order by will not "store" and order that document. Next, in my chat application I created a field with the Timestamp constructor that Firebase offers. That allowed me to order the documents in the createdAt order.

My code for the ChatBox file: Chatbox.js

import { collection, query, onSnapshot, orderBy } from "firebase/firestore";
//OTHER CODE
useEffect(() => {
    onSnapshot(query(collection(db, "messages"), orderBy("createdAt")), (snapshot) => {
      setMessages(snapshot.docs.map((doc) => doc.data()));
    });
  }, []);

SendMessage.js

import { collection, addDoc, Timestamp } from "firebase/firestore";
//OTHER CODE
const [userMessage, setUserMessage] = useState("");
  async function sendUserMessage(e) {
    const auth = getAuth();
    e.preventDefault();
    const { uid, photoURL } = auth.currentUser;
    await addDoc(collection(db, "messages"), {
      text: userMessage,
      photoURL,
      uid,
      createdAt: Timestamp.fromDate(new Date()),
    });
  }

Hope this makes sense.

CodePudding user response:

In JS API v9 we have to perform everything in a functional way. To order the collection before you attach a listener, you need to perform a query. A query can take a reference, order the results and pass the results to the caller.

In other words, your code should look like this:

import { onSnapshot, collection, orderBy, query, limit } from "firebase/firestore";
//OTHER CODE
useEffect(() => {
    onSnapshot(query(collection(db, "messages"), orderBy("YOUR_FIELD")), (snapshot) => {
      setMessages(snapshot.docs.map((doc) => doc.data()));
    });
  }, []);

Change YOUR_FIELD with the reference to any field you want to use to order the results. What we are doing here is:

  • getting a reference to a collection
  • asking firestore to perform a query on that collection, ordering the results by a field
  • attaching a listener to the results

CodePudding user response:

Hi can you can try this :

useEffect(() => {
    onSnapshot(query(collection(db, "messages").orderBy('createdAt').startAfter(today)), 
      (snapshot) => {
      setMessages(snapshot.docs.map((doc) => doc.data()));
    }); 
    }, []);
  • Related