How can I display all of these fields? - reactjs

I can already retrieve the document and it shows in the console but how can I retrieve the individual fields so I can display it in the screen?
useEffect(() => {
const unsubscribe = firestore
.collection("orders")
.where("uid", "==", user.id)
.onSnapshot((snapshot) => {
console.log(snapshot.docs.map((doc) => ({ id: doc.data() })));
});
return () => {
unsubscribe();
};
}, []);
i wanted to get these individual fields and how can I map through the "items"array?
This is what it shows in the console.log and I wanted to access and display the individual fields like the address, items, and delivery date
Document Data as JSON:
[{"id":{"displayName":"Jenn ","items":[{"productPrice":"130","productUserHandler":null,"createdDate":{"seconds":1617787002,"nanoseconds":70000000},"qty":1,"productDesc":"Cheese ","productName":"Pizza","productImg":"https://firebasestorage.googleapis.com/v0/b/ajc-pizza.appspot.com/o/product-images%2Ftunapizza.jpg?alt=media&token=e307d9aa-bc67-4262-94e7-7c7346cc933b","documentID":"MS1PmRyGTWitCaLtV5Xk"},{"documentID":"ndxxdJyS40aRcndJLg9E","productUserHandler":null,"qty":1,"productPrice":"130","productName":"Pizza","productImg":"https://firebasestorage.googleapis.com/v0/b/ajc-pizza.appspot.com/o/product-images%2Fvegetablepizza.jpg?alt=media&token=6f02cd14-6bd9-40dd-9b31-95925578422b","createdDate":{"seconds":1617787021,"nanoseconds":448000000},"productDesc":"Vegetables / Cheese"}],"deliveryDate":"2021-05-08","orderCreatedAt":{"seconds":1619862395,"nanoseconds":463000000},"userID":"kGhSlhM2pIgL9srfXviw9Xew4mI3","total":260,"phone":"+63 9353 276961","address":"US"}},{"id":{"phone":"(555) 555-1234","items":[{"productImg":"https://firebasestorage.googleapis.com/v0/b/ajc-pizza.appspot.com/o/product-images%2Ftunapizza.jpg?alt=media&token=e307d9aa-bc67-4262-94e7-7c7346cc933b","qty":2,"createdDate":{"seconds":1617787002,"nanoseconds":70000000},"documentID":"MS1PmRyGTWitCaLtV5Xk","productName":"Tuna Pizza","productPrice":"130","productUserHandler":null,"productDesc":"Tuna / Cheese "}],"deliveryDate":"2021-05-03","address":"US","displayName":"Jenn ","total":260,"userID":"kGhSlhM2pIgL9srfXviw9Xew4mI3","orderCreatedAt":{"seconds":1619857372,"nanoseconds":32000000}}}]

There's no field named as uid in the document. So please make sure you add it first else the 'where' query won't work as intended. You cannot fetch a single field from Firestore. First fetch the whole document and then use the relevant data.
useEffect(() => {
const unsubscribe = firestore
.collection("orders")
.where("uid", "==", user.id)
.onSnapshot((snapshot) => {
const userOrders = snapshot.docs.map((doc) => ({ [doc.id]: doc.data() }));
console.log(userOrders);
// Logging items of first order
// console.log(userOrders[0]["items"])
});
return () => {
unsubscribe();
};
}, []);
Please use [doc.id]: doc.data() in the map so the keys will be the order IDs (document IDs). When it comes to rendering those on your webpage, you need to use a map function to render all orders first and another map function inside of each to render the items. Let me know if you have further questions.

Related

React doesn't re-render my component when the array is changed?

I've set different options for sorting various listings, and i've set an empty array for my listings. using firebase for backend, so basically everything is working, but the data isn't displayed after useEffect does it's work. as soon as I change the sort option the listings appear. after refreshing it is the same again.
I'm passing the listings and sort as props to another child component which is a grid layout. Everytime I've to manually change the sort so see data, how can it be so that it automatically show's the data according to the sort option.
const [sort, setSort] = useState("option1");
const [listings, updateListings] = useState([]);
const db = getFirestore();
const colRef = collection(db, "Listing");
useEffect(() => {
let defaultListings = [];
getDocs(colRef)
.then((snapshot) => {
snapshot.docs.forEach((doc) => {
defaultListings.push({ ...doc.data(), id: doc.id });
});
})
.catch((err) => {
console.log(err.message);
});
updateListings(defaultListings);
}, []);
return(<Listing list = {listings} sortoption={sort} />)
this listing component shows the grid
i've tried adding dependencies, but it results in an infinite loop, while without any dependencies the component doesn't show anything.
You need to call updateListings inside then, otherwise it will run before you modify the defaultListings array.
So:
getDocs(colRef)
.then((snapshot) => {
snapshot.docs.forEach((doc) => {
defaultListings.push({ ...doc.data(), id: doc.id });
});
updateListings(defaultListings); // 👈
})
.catch((err) => {
console.log(err.message);
});

How to map over multiple collections in firebase that starts with specific text?

I'm trying to fetch muliple collection from firebase that starts with specific text, but i can't fetch them all, It just fetch only one collection
this a picture of firebase collections that i want to fetch starts with 'Buyer-Cart'
const Uid = auth.currentUser.uid;
useEffect(() => {
fs.collection("Buyer-Cart "+Uid)
.get()
.then((Snapshot) => {
const data = Snapshot.docs.map((doc) => {
return doc.data();
});
setOrderIds(data);
});
}, []);

The screen doesn't get updated but get console log when database get updated

I am building backend app, when the order is placed I get console log but the screen doesn't get updated and also the back button(react navigation), response after few seconds.
const GetdataUsers = async () => {
let grabbedData1 = [];
let customerList1 = [];
await firebase
.database()
.ref(`/serviceProvider/${user1.uid}/franchise/customers`)
.orderByKey()
.on("value", (snapshot) => {
customerList1.push(snapshot.val());
// setCustomerList(customerList1);
if (customerList1) {
Object.keys(customerList1).map(function (key) {
let y = customerList1[key];
Object.keys(y).map(function (key2) {
let x = y[key2]; // get all customer id
// From that id fetch all the orders they have
firebase
.database()
.ref(`/orders/${x}`)
.orderByKey()
.on("value", (snapshot, key) => {
grabbedData1.push(snapshot.val());
console.log("grabbedData1....",grabbedData1);
// Grab all orders from the customers and set it
setShowloading(false);
setOrders(grabbedData1);
});
})
});
}
});
};
useEffect(() => {
GetdataUsers();
}, []); // [orders] tried this way also
When placing orders in bracket as shown above back button freezes and doesn't get any update . Also tried returning the data from function and setorder inside useEffect but stuck in a loop.
At first query I fetch all the customers Ids that they have which is
"x" (let x = y[key2];) then another query for all orders that customer
(x) have and then store it to orders (setOrders(grabbedData1);) and to
print on the app
Issues I see with the code:
You care mutating arrays in the getDataUsers function.
You've a set of nested firebase subscriptions that necessarily depend on the just updated customerList.
You don't unsubscribe from any firebase snapshot subscriptions.
I think it would be better to split this into two separate actions, or effects, one to handle the user's uid changing to set the current customerList state, and a second to handle fetching/updating the orders state when the customerList state updates.
Example:
Update the customer list when user changes.
useEffect(() => {
const unsubscribe = firebase
.database()
.ref(`/serviceProvider/${user1.uid}/franchise/customers`)
.orderByKey()
.on("value", (snapshot) => {
setCustomerList(snapshot.val());
});
return unsubscribe;
}, [user1.uid]);
Update the orders when customer list updates.
useEffect(() => {
const innerSubscriptions = [];
if (customerList) {
setOrders([]); // <-- clear orders for new customers list
Object.values(customerList).forEach((customer) => {
Object.values(customer).forEach((id) => {
const unsubscribe = firebase
.database()
.ref(`/orders/${id}`)
.orderByKey()
.on("value", (snapshot, key) => {
const order = snapshot.val();
// Grab all orders from the customers and merge
setOrders((orders) => [...orders, order]);
});
innerSubscriptions.push(unsubscribe);
});
});
}
return () => {
innerSubscriptions.forEach((unsubscribe) => unsubscribe());
};
}, [customerList]);
You have made an async function but you haven't used the await keyword. Also you'll have to create a state for loader and conditionally render a loader component till you have fetched all the data.

Only first element is showing state updates until external event

Related and an almost direct extension of my earlier question
I am using useEffect to run a function that grabs data from firebase.
The data is grabbed, however only the first element appears to show the additional information added to the state.
const [expenses, setExpenses] = useState([]);
const roster = [];
var db = firebase.firestore();
React.useEffect(() => {
const getRoster = async () => {
db.collection("Roster")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
var data = doc.data();
data.ID = doc.id;
roster.push(data);
});
// setExpenses(roster);
// console.log("expenses", expenses);
// console.log("roster", roster);
})
This is working as expected, the commented out code was the solution to my previous question.
I added in the code below and experienced my new issue.
.then(() => {
roster.forEach((member) => {
let total = 0;
db.collection("Attendance Entries")
.where("attendees", "array-contains", member.ID)
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
total++;
member.total = total;
});
setExpenses(roster);
});
});
});
};
getRoster();
}, []);
The first element shows the "member.total" on the inital load, the others only appear after the state is changed. Not sure why that is the case..
Thank you for the help!
Example of what I am seeing on initial load
I don't quite follow all of your code, but I see a possible issue with the way you enqueue state updates in the forEach loop in the section of code you say you've an issue with. When you enqueue state updates in a loop you must use a functional state update so each enqueued update doesn't blow away (overwrite) the previous state.
You can iterate the roster array you've previously computed and then compute the docs total for each member and mutate the member object, then use a functional state update to append the new member object to the expenses state array.
.then(() => {
roster.forEach((member, index) => {
let total = 0;
db.collection("Attendance Entries")
.where("attendees", "array-contains", member.ID)
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
total++;
});
member.total = total;
setExpenses(expenses => expenses.concat(member));
});
});
});

How to insert array from another query as parameter in DB call FIREBASE

I'm trying to build compound query in Expo react native - firestore.
I have 2 collections in firebase. First "node" is userID and second are IDs of places that had been discovered by this user. Then, I need to take this array of place IDs and pass it as parameter in 2nd query where I got name of each place stored in collection named "databaseOfPlaces". (I want to make scrollable view with names, so maybe I should add listener later on?)
My solution is not working very well. Can you help me? Is this the right way, or is there another way how to save DB call?
Thank you very much.
This is my code:
async componentDidMount() {
db.collection("placesExploredByUsers") // default
.doc("mUJYkbcbK6OPrlNuEPzK") // default
.collection(auth.currentUser.uid)
.get()
.then((snapshot) => {
if (snapshot.empty) {
alert("No matching documents.");
return;
}
const users = [];
snapshot.forEach((doc) => {
const data = doc.data();
users.push(data);
});
this.setState({ users: users });
})
.catch((error) => alert(error));
db.collection("databaseOfPlaces")
.where('placeID','in',this.state.users)
.get()
.then((snapshot) => {
if (snapshot.empty) {
alert("No matching documents.");
return;
}
const places = [];
snapshot.forEach((doc) => {
const data = doc.data();
places.push(data);
});
this.setState({ places: places });
})
.catch((error) => alert(error));
}
Data is loaded from Firestore (and most modern cloud APIs) asynchronously. By the time your second query now runs, the results for the first query are not available yet.
Because of this, any code that needs the results from the first query, will need to be inside the then() callback of that query.
So:
async componentDidMount() {
db.collection("placesExploredByUsers") // default
.doc("mUJYkbcbK6OPrlNuEPzK") // default
.collection(auth.currentUser.uid)
.get()
.then((snapshot) => {
if (snapshot.empty) {
alert("No matching documents.");
return;
}
const users = [];
snapshot.forEach((doc) => {
const data = doc.data();
users.push(data);
});
this.setState({ users: users });
db.collection("databaseOfPlaces")
.where('placeID','in', users)
.get()
.then((snapshot) => {
if (snapshot.empty) {
alert("No matching documents.");
return;
}
const places = [];
snapshot.forEach((doc) => {
const data = doc.data();
places.push(data);
});
this.setState({ places: places });
})
})
.catch((error) => alert(error));
}

Resources