Home > Enterprise >  How to add the data from document users to document orders using usersID?
How to add the data from document users to document orders using usersID?

Time:08-12

Trying to list orders in a table. However I have the userId embedded in the orders documents{orderItemss, orderTotal, shippingFee,userID}, and not the user's name, email, contact, etc.

How do I dynamically get the user fName, lName, etc to join OrderDetails and display the full object within a table?

enter image description here

WHat i tried was:

import React, { useEffect, useState } from "react";
import Layout from "../components/Layout";
import { collection, query, where, getDocs } from "firebase/firestore";
import { db } from "../utils/firebase";

const Orders = () => {
    const [users, setUsers] = useState([]);
    const [orders, setOrders] = useState([]);
    const ordersCollectRef = query(collection(db, "Orders"));
    const userCollectionRef = query(collection(db, "User"));
    useEffect(() => {
        const getUsers = async () => {
            const data = await getDocs(userCollectionRef);
            setUsers(
                data.docs.map((doc) => ({
                    ...doc.data(),
                    id: doc.id,
                }))
            );
        };
        getUsers();
        const getOrders = async () => {
            const orderData = await getDocs(ordersCollectRef);

            setOrders(
                orderData.docs.map((order) => ({
                    ...order.data(),
                }))
            );
        };
        getOrders();
    }, []);

....

<table className="table-auto w-full text-base text-left text-gray-900">
                    <thead className="text-sm text-gray-700 uppercase bg-gray-50">
                        <tr>
                            <th scope="col" className="py-3 px-6">
                                First
                            </th>
                            <th scope="col" className="py-3 px-6">
                                Last Name
                            </th>
                            <th scope="col" className="py-3 px-6">
                                Contact
                            </th>
                            <th scope="col" className="py-3 px-6">
                                Address
                            </th>
                            <th scope="col" className="py-3 px-6">
                                Order Total
                            </th>
                            <th scope="col" className="py-3 px-6">
                                Shipping Fee
                            </th>
                            <th scope="col" className="py-3 px-6">
                                Grand Total
                            </th>
                            <th scope="col" className="py-3 px-6">
                                Actions
                            </th>
                        </tr>
                    </thead>
                    <tbody>
                        {orders.map((order, i) => (
                            <tr className="bg-white border-b" key={i}>
                                <th
                                    scope="row"
                                    className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap"
                                >
                                    {/* {user.fName} */}
                                </th>
                                <td></td>
                                <td className="py-4 px-6">{/* {user.lName} */}</td>
                                <td className="py-4 px-6">
                                    {/* {user.contact.primary
                                        ? user.contact.primary
                                        : user.contact.secondary} */}
                                </td>
                                {/* <td className="py-4 px-6">
                                    {user.shippingAddress.street},<br />
                                    {user.shippingAddress.parish}
                                </td> */}
                                <td className="py-4 px-6">{order.orderTotal}</td>
                                <td className="py-4 px-6">{order.shippingFee}</td>
                                <td className="py-4 px-6">{order.grandTotal}</td>
                                <td className="py-4 px-6  items-center  justify-center flex space-x-2 text-white font-medium font-serif">
                                    <button className="w-16 h-8 rounded-md bg-blue-500">
                                        {" "}
                                        edit
                                    </button>{" "}
                                    <button className="w-16 h-8 rounded-md bg-red-500">
                                        delete
                                    </button>
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </table>

i honestly havent made an attempt to join the objects/lists. Every approach I think of is flaud from the beginningenter image description here

CodePudding user response:

There are two ways of going about it. The more efficient way is as follows:

In your submit order handler, after you create an order document using addDoc(), you can store the id of the newly created document as an element in the orders array of the user document corresponding to the currently logged in user. That way, when you want to display the orders of a user, you only need to fetch those documents whose id is mentioned inside the orders array.

If you want to work with fetching all users and all orders at the same time, you will have to do it inside a useEffect call, with dependencies as [users, orders] with the following callback:

if(users.length === 0 && orders.length === 0) return; // return if run before fetching

for(const user in users) {
    const userID = user.id;
    const ordersByUser = orders.filter(order => order.userID === userID);
    // Make a new array of the users with details of their orders here using another state variable
}

Let me know if you need help with more code.

CodePudding user response:

If you want to combine the data from two collections then you have to do it in javascript. I'm not really sure what you want to achieve but here's my take how you will combine the data based from the userID field. See code below:

  const [orders, setOrders] = useState([]);
  const ordersCollectRef = query(collection(db, "Orders"));
  const userCollectionRef = query(collection(db, "User"));
  useEffect(() => {
      const getOrders = async () => {
        const orderData = await getDocs(ordersCollectRef);
        const usersData = await getDocs(userCollectionRef);
        const combinedData = [];
        var users = usersData.docs.map((doc) => ({
          ...doc.data(),
          id: doc.id,
        }))

        var orders = orderData.docs.map((order) => ({
            ...order.data(),
        }))

        orders.forEach((order) => {
          users.forEach((user) => {
            if (order.userID == user.id) {
              combinedData.push({...order, user})
            }
          })
        })
        // console.log(combinedData)
        
        setOrders(
          combinedData
        );
      };
      getOrders();
  }, []);

Rendering:

<table className="table-auto w-full text-base text-left text-gray-900">
    <thead className="text-sm text-gray-700 uppercase bg-gray-50">
        <tr>
            <th scope="col" className="py-3 px-6">
                First
            </th>
            <th scope="col" className="py-3 px-6">
                Last Name
            </th>
            <th scope="col" className="py-3 px-6">
                Contact
            </th>
            <th scope="col" className="py-3 px-6">
                Address
            </th>
            <th scope="col" className="py-3 px-6">
                Order Total
            </th>
            <th scope="col" className="py-3 px-6">
                Shipping Fee
            </th>
            <th scope="col" className="py-3 px-6">
                Grand Total
            </th>
            <th scope="col" className="py-3 px-6">
                Actions
            </th>
        </tr>
    </thead>
    <tbody>
        {orders.map((order, i) => (
            <tr className="bg-white border-b" key={i}>
                <th
                    scope="row"
                    className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap"
                >
                    {order.user.fName}
                </th>
                <td className="py-4 px-6">{order.user.lName}</td>
                <td className="py-4 px-6">
                    {order.user.contact.primary
                        ? order.user.contact.primary
                        : order.user.contact.secondary}
                </td>
                <td className="py-4 px-6">
                    {order.user.shippingAddress.street},<br />
                    {order.user.shippingAddress.parish}
                </td>
                <td className="py-4 px-6">{order.user.fName}</td>
                <td className="py-4 px-6">{order.shippingFee}</td>
                <td className="py-4 px-6">{order.grandTotal}</td>
                <td className="py-4 px-6  items-center  justify-center flex space-x-2 text-white font-medium font-serif">
                    <button className="w-16 h-8 rounded-md bg-blue-500">
                        {" "}
                        edit
                    </button>{" "}
                    <button className="w-16 h-8 rounded-md bg-red-500">
                        delete
                    </button>
                </td>
            </tr>
        ))}
    </tbody>
</table>

Result: enter image description here

Note: There are many ways to combine objects, this is just one of them.

  • Related