I have this on my firestore:
and this is how I'm retrieving the data. I simply copied it from the firebase documentation and it keeps on saying "No such document"
useEffect(() => {
const Ref = firestore.collection("business").doc("business-store");
const doc = Ref.get();
if (!doc.exists) {
console.log("No such document!");
} else {
console.log("Document data:.", doc.data());
}
}, []);
You can try in this way, it should give you the result:
useEffect(() => {
firestore.collection("business").doc("business-store").get().then(doc=>{
if (!doc.exists) {
console.log("No such document!");
} else {
console.log("Document data:.", doc.data());
}
}).catch(error={})
}, []);
Related
According to the documentation from firebase you can get a document very simply by using get()
But for some reason in my code it always displays that there's no such document, even though it does exist, this is what I'm doing:
useEffect(() => {
console.log(user, "This is the user UID:"+user.uid)
const userDoc = db.collection('usuarios').doc(user.uid);
const doc = userDoc.get();
if (!doc.exists) {
console.log('No such document!');
}
else {
userDoc
.onSnapshot(snapshot => {
const tempData = [];
snapshot.forEach((doc) => {
const data = doc.data();
tempData.push(data);
});
setUserData(tempData);
})
}
}, [user]);
This is what the console.log() shows:
This is how it looks in firebase:
const doc = userDoc.get();
if (!doc.exists) {
.get returns a promise, so you're checking the .exists property on a promise, which is undefined. You will need to wait for that promise to resolve, either with .then:
userDoc.get().then(doc => {
if (!doc.exists) {
// etc
}
});
Or by putting your code in an async function and awaiting the promise:
const doc = await userDoc.get();
if (!doc.exists) {
// etc
}
If you're using the firebase 8 web version, the userDoc.get() returns a promise, not the document:
userDoc.get().then((doc) => {
if (!doc.exists) {
console.log('No such document!');
} else {
const tempData = [];
const data = doc.data();
tempData.push(data);
setUserData(tempData)
console.log('it worked')
}
}).catch((error) => {
console.log("Error getting document:", error);
});
You can get more info about promises in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises.
In your code you are using the get method to fetch user data and get doesn't provide a snapshot. also, you missed that get() will return a promise so you have to handle using async-await or .then etc.
useEffect(() => {
console.log(user, "This is the user UID:"+user.uid);
getUser(user.uid).then(userData => {
setUserData(userData);
});
}, [user]);
const getUser = async (id) => {
try {
const user = await db.collection('usuarios').doc(id).get();
const userData = user.data();
return userData;
} catch (err){
console.log('Error during get user, No such document!');
return false;
}
I am trying to get all the documents from a Firestore collection. I am following their docs to do so. However, nothing happens. I do not see anything console-logging or any errors whatsoever. Basically, nothing happens, as if the get() function is not working. I am clueless as to what is going on.
Here's the code with the get(). It is written in ReactJS with hooks:
import React, { useState, useEffect } from 'react';
import firebase from '../firebase.js';
import './Messages.css';
function Messages (props) {
const [messages, setMessages] = useState([]);
const [customers, setCustomers] = useState([]);
useEffect(() => {
const query = firebase
.firestore()
.collection("Chats")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
if (doc.exists) {
console.log(doc)
} else {
console.log('nothing')
}
console.log(doc.id, " => ", doc.data());
});
}).catch((error) => {
console.log("Error getting documents: ", error);
});
}, []);
Similarly, the same thing was happening to the onSnapShot function that I tried to use as follows:
useEffect(() => {
const unsub = query.onSnapshot(async querySnapshot => {
if (querySnapshot.docChanges().length > 0) {
const data = querySnapshot.docs.map((doc) => {
return { body: doc.data(), id: doc.id }
}
);
const allData = await Promise.all(data)
setCustomers(allData);
} else { console.log("no data") }
}, (error) => {
console.log("Error listening to documents: ", error);
})
return () => {
unsub();
};
}, []);
The Customers state is empty and console-logging from anywhere within Querysnapshot function does not work. Strangely, however, similar set-ups/codes work in my other components. Adding dependencies or placing the code into another function (fetchData()) and calling it within useEffect did not work. I am also certain it is not an issue with Rules as I am accessing Firestore as an admin for which I have an appropriate Rule set up (match /{documents=**} { allow write, read: if request.auth.token.admin == true; }). I am clueless as to what is going on. Please help.
P.S. The following code does work within the useEffect in the same component, however, but since I can not figure out how to get rid of duplicates that I get from the query in the customers state (tried array.includes and indexof but failed) as I kept getting only one same object, I am ditching the following code in favor of one of the above.
const query = firebase.firestore()
.collectionGroup('Messages')
.orderBy("timestamp", "desc")
const unsub = query.onSnapshot((snapshot) => {
if (snapshot.empty) {
console.log('No matching documents.');
return;
}
snapshot.docs.map((doc) => {
console.log("1")
if (customers.length ) {
console.log("1b")
customers.map((customer) => {
console.log("2")
if (customer.uid.indexOf(doc.data().uid) === -1) {
console.log("3")
setCustomers(prevFiles => ([...prevFiles, {
name: doc.data().name, uid: doc.data().uid
}]))
}
})
} else {
console.log("4")
setCustomers([{name: doc.data().name, uid: doc.data().uid}])
}
});
}, (error) => {
console.log('Error getting messages', error);
})
I figured it out. This might be very useful for somebody who is in a similar situation to know as this does not seem to be explained in the Firestore docs.
Anyways, the reason nothing was happening and console.logging was not working was because the query was empty. So, make sure to always check that your collection has documents which in turn have some information. The documents that I was trying to get contained a collection and named after user ids which I needed. However, since they did not really contain any information, they could not be retrieved. And, I did not know that. I simply needed the names of the documents, the uids.
One way you can check if your snapshot is empty is as follows:
if (snapshot.empty) {
console.log('No matching documents.');
return;
}
In my code, it looks like this:
const query = firebase
.firestore()
.collection("Chats")
.get()
.then((querySnapshot) => {
if (querySnapshot.empty) {
console.log('No matching documents.');
return;
}
querySnapshot.forEach((doc) => {
if (doc.exists) {
console.log(doc)
setCustomers(prevFiles => ([...prevFiles, {
id: doc.data().id, data: doc.data()
}]))
} else {
console.log('nothing')
}
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
}).catch((error) => {
console.log("Error getting documents: ", error);
});
Basically, it will never get to the forEach part if it is empty.
Hope this sheds some light on some confusion that someone might have about the docs in collections. They must contain info to be retrievable. Happy coding.
Here is how my savedLinksData array prints in my console:
Here is my code that attempts to get the linkType value:
{savedLinksData.map((saved) => {
return <h1>{saved.linkType}</h1>;
})}
What I'm doing wrong?
I think there may be something wrong with the way I stored the values in the array. It doesn't look like the value are inside of the array.
Picture of console.log("----->", saved)
const [savedLinksData, setSavedLinksData] = useState([]);
// query for saved links data
useEffect(() => {
if (user) {
async function fetchData() {
const request = await db
.collection("users")
.doc(user)
.collection("saved")
.onSnapshot((snapshot) =>
setSavedLinks(
snapshot.docs.map((doc) => ({ ...doc.data(), id: doc.id }))
)
);
}
fetchData();
} else {
setSavedLinks([]);
}
}, [user]);
useEffect(() => {
if (savedLinks.length > 0) {
let newArray = [];
savedLinks.map((saved) => {
db.collection("users")
.doc(saved.savedUser)
.collection("links")
.doc(saved.savedLinkId)
.get()
.then(function (doc) {
if (doc.exists) {
// console.log("Document data:", doc.data());
newArray.push(doc.data());
// setSavedLinksData([...savedLinksData, doc.data()]);
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
})
.catch(function (error) {
console.log("Error getting document:", error);
});
});
setSavedLinksData(newArray);
}
}, [savedLinks]);
PROBLEM: I need to access the linkTitle values for each object in my array.
Here is how my savedLinksData array is structured:
And here is my code:
{savedLinksData.map((saved, key) => (
<h1>{saved.linkType}</h1>
))}
Full Code:
// query for saved links data
useEffect(() => {
if (user) {
async function fetchData() {
const request = await db
.collection("users")
.doc(user)
.collection("saved")
.onSnapshot((snapshot) =>
setSavedLinks(
snapshot.docs.map((doc) => ({ ...doc.data(), id: doc.id }))
)
);
}
fetchData();
} else {
setSavedLinks([]);
}
}, [user]);
useEffect(() => {
if (savedLinks.length > 0) {
let newArray = [];
savedLinks.map((saved) => {
db.collection("users")
.doc(saved.savedUser)
.collection("links")
.doc(saved.savedLinkId)
.get()
.then(function (doc) {
if (doc.exists) {
// console.log("Document data:", doc.data());
newArray.push(doc.data());
// setSavedLinksData([...savedLinksData, doc.data()]);
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
})
.catch(function (error) {
console.log("Error getting document:", error);
});
});
setSavedLinksData(newArray);
}
}, [savedLinks]);
console.log("RETURNED LINKS DATA", savedLinksData);
console.log("SAVED", savedLinks);
You can do {savedLinksData.map((saved, key) => ( <h1>{saved.linkInfo.linkTitle}</h1> ))}
Ok so i use the useEffect to get firebase firestore data. This is my hook code:
const [campaign, setCampaigns] = useState([])
useEffect(() => {
var docRef = db.collection("campaigns").doc(slug);
docRef.get().then(function(doc) {
if (doc.exists) {
console.log("Document data:", doc.data());
setCampaigns(doc.data())
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});
},[]);
console.log(campaign[0].startDate.seconds) // gives the error stated below
console.log(campaign.images[0].url)// gives the error stated below
The response is:
I can get access to all the top level properties such as body, campaignPolicy etc. but if I do
TypeError: Cannot read property 'seconds' of undefined
If I do campaign.startDate.seconds i get same error:
TypeError: Cannot read property 'seconds' of undefined
Full minimal code:
const ReviewComponent = (props) => {
const [open, setOpen] = useState(false)
const [campaigns, setCampaigns] = useState([])
const [currentCampaign, setCurrentCampaign] = useState([])
//First useEffect hook
const tempDoc = []
useEffect(() => {
var docRef = db.collection("campaigns");
docRef.get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
tempDoc.push({ id: doc.id, ...doc.data() })
// doc.data() is never undefined for query doc snapshots
setCampaigns(tempDoc)
});
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});
},[]);
//Second use effect hook
useEffect(() => {
const docRef = db.collection("campaigns").doc(slug);
docRef.get().then(function(doc) {
if (doc.exists) {
console.log("Document data:", doc.data());
setCurrentCampaign(doc.data())
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});
},[]);
const handleOpen = () => {
setOpen(true)
};
const handleClose = () => {
setOpen(false);
};
if(currentCampaign[0]) { // Or if(campaign[0])
console.log(currentCampaign)
}
return(
<Typography>
{currentCampaign.reviews[0].text}
</Typography>
)
You are trying to access your data before they are retrieved. Here is what happens:
// First render
You set your state as an empty array
You declare an effect with a callback that will be called after the first render
You try to access a value that is indeed undefined (your array is empty at this point) and your app crash
// Second render
Your code crash at the first render but if it didn't:
Your state now contains your data
Your effect will not be called as you have an empty dependency array
You can use your data
To make your code work, and you should do it every time you load data asynchronously, is to check that your data are loaded.
const [campaign, setCampaigns] = useState([]);
useEffect(() => {
const docRef = db.collection("campaigns").doc(slug);
docRef.get().then(function(doc) {
if (doc.exists) {
console.log("Document data:", doc.data());
setCampaigns(doc.data())
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});
},[]);
if(campaign.length > 0) { // Or if(campaign[0])
console.log(campaign[0].startDate.seconds)
console.log(campaign[0].images[0].url)
}
The default value of campaign is empty array and it is set after few time from firebase store.
So you should check campaign state what is empty or has value.
if (campaign.length == 0)
console.log(campaign[0].startDate.seconds);