Can't fetch all data from Firestore React-Native - reactjs

I can't fetch all data from Firestore in my react native app. I can fetch data when I add a limit(200) parameter but when I take away the limit parameter my app crashes. I need to display all the data and I don't know what I'm doing wrong, here is my code:
const listingsRef = firebase.firestore().collection(ServerConfiguration.database.collection.LISTINGS);
if (categoryId === '') {
console.log('Kommer vi hit???');
return listingsRef
.where('isApproved', '==', isApproved)
.limit(2000)
.onSnapshot((querySnapshot) => {
const data = [];
if (querySnapshot !== undefined) {
querySnapshot.forEach((doc) => {
const listing = doc.data();
if (favorites && favorites[doc.id] === true) {
listing.saved = true;
}
data.push({ ...listing, id: doc.id });
});
console.log('KOMMERR datan? : ', data);
callback(data);
}
});
}
I have tried to use get instead of on Snapshot, and I get the same results. I have been stuck for days!

You can replace the limit with getting and getting all the records that satisfy your condition.
const listingsRef = firebase.firestore().collection(ServerConfiguration.database.collection.LISTINGS);
if (categoryId === '') {
console.log('Kommer vi hit???');
return listingsRef
.where('isApproved', '==', isApproved)
.get()
.onSnapshot((querySnapshot) => {
const data = [];
if (querySnapshot !== undefined) {
querySnapshot.forEach((doc) => {
const listing = doc.data();
if (favorites && favorites[doc.id] === true) {
listing.saved = true;
}
data.push({ ...listing, id: doc.id });
});
console.log('KOMMERR datan? : ', data);
callback(data);
}
});
}
But its always a good idea to paginate your results when you have large amount of data

Related

Asynchronous Function In NextAuth Completing Before Value Returned

On signin, I'm attempting to query FirestoreDB and then return the user data or null.
I'm trying to do this with async await, but the dependent code runs before the db query has been completed. This can be seen when "CORRECT," (right credentials) is console logged after the empty user details (not complete).
Thanks,
This is my code:
let data = await db.collection('users').where("email", "==", email).get().then(querySnapshot => {
console.log("SOMETHING")
let arr = []
querySnapshot.docs.map(doc => arr.push(doc.data()))
console.log(arr)
// console.log(sc.decrypt(arr[0].password))
if (arr[0].email == email) {
bcrypt.compare(password, arr[0].password, (err, match) => {
if (match) {
console.log("CORRECT")
return arr[0]
} else {
if (err) {
console.log(err)
}
console.log("INCORRECT")
return null
}
})
}
})
console.log("DATA " + data)
return data ? data : null
An hour of searching, but 2 minutes after I post I figure it out.
Here is the working code for anyone in the same boat:
let data = new Promise((resolve, reject) => {
db.collection('users').where("email", "==", email).get().then(querySnapshot => {
console.log("SOMETHING")
let arr = []
querySnapshot.docs.map(doc => arr.push(doc.data()))
console.log(arr)
// console.log(sc.decrypt(arr[0].password))
if (arr[0].email == email) {
bcrypt.compare(password, arr[0].password, (err, match) => {
if (match) {
console.log("CORRECT")
resolve(arr[0])
} else {
if (err) {
console.log(err)
}
console.log("INCORRECT")
resolve(null)
}
})
}
})
})
Promise.all([data]).then(async () => {
console.log(await data)
})
return data ? data : null

Firebase: Problem getting data from nested onSnapshot

I have the following useEffect set up to fetch some data from firebase to populate a flatlist
useEffect(() => {
return db
.collection('accounts')
.doc(currentAccountId)
.collection('shops')
.doc(currentShopId)
.collection('sensors')
.onSnapshot((querySnapshot) => {
const list = [];
querySnapshot.forEach((doc) => {
const { sensorReadingsId } = doc.data();
// This works, but doesn't load the additional data I need.
// list.push({ ...{ id: doc.id }, ...doc.data() });
// This doesn't seem to load anything.
db.collection('sensors')
.doc(sensorReadingsId.toString())
.onSnapshot((documentSnapshot) => {
list.push({ ...{ id: doc.id }, ...doc.data(), ...documentSnapshot.data() });
});
});
setSensorsData(list);
console.log(sensorsData);
setLoading(false);
});
}, [currentAccountId, currentShopId]);
Here's the problem: my flatlist doesn't load anything. When I initially load the screen, that console.log outputs an empty array. If I force it to re-render by saving the screen file, the array is correctly populated.
As noted in that comment, if I just use list.push({ ...{ id: doc.id }, ...doc.data() }); instead of db.collection('sensors')... it loads the sensors fine, but without the additional data that I need.
How do I resolve this? Thanks in advance!
Solution: As #Rajitha Udayanga has pointed out, checking the length of the first querysnapshot against the list array is a great way to check whether or not all the data has been loaded. Here's the working code (note the conditional that setSensorsData has been moved into):
useEffect(() => {
return db
.collection('accounts')
.doc(currentAccountId)
.collection('shops')
.doc(currentShopId)
.collection('sensors')
.onSnapshot((querySnapshot) => {
const list = [];
querySnapshot.forEach((doc) => {
const { sensorReadingsId } = doc.data();
db.collection('sensors')
.doc(sensorReadingsId.toString())
.onSnapshot((documentSnapshot) => {
list.push({ ...{ id: doc.id }, ...doc.data(), ...documentSnapshot.data() });
// Fix is here:
if (querySnapshot.docs.length === list.length) {
setSensorsData(list);
console.log(sensorsData);
setLoading(false);
}
});
});
});
}, [currentAccountId, currentShopId]);
Disclaimer: I have zero experience with React.
In Angular I deal with such issues using RxJS's combineLatest.
However, you can try this one:
useEffect(() => {
return db
.collection('accounts')
.doc(currentAccountId)
.collection('shops')
.doc(currentShopId)
.collection('sensors')
.onSnapshot((querySnapshot) => {
const list = [];
const useValues = () => {
if (list.some(value => value === undefined)) {
return; // not everything has loaded yet - abort
}
setSensorsData(list);
console.log(sensorsData);
setLoading(false);
}
querySnapshot.forEach((doc, index) => {
list.push(undefined);
const { sensorReadingsId } = doc.data();
db.collection('sensors')
.doc(sensorReadingsId.toString())
.onSnapshot((documentSnapshot) => {
list[index] = ({ id: doc.id, ...doc.data(), ...documentSnapshot.data() });
useValues();
});
});
});
}, [currentAccountId, currentShopId]);
And don't forget to detach the listeners when you don't need them anymore.
useEffect(() => {
return db
.collection('accounts')
.doc(currentAccountId)
.collection('shops')
.doc(currentShopId)
.collection('sensors')
.onSnapshot((querySnapshot) => {
const list = [];
querySnapshot.forEach((doc) => {
const { sensorReadingsId } = doc.data();
db.collection('sensors')
.doc(sensorReadingsId.toString())
.onSnapshot((documentSnapshot) => {
const newData = {
...{ id: doc.id },
...doc.data(),
...documentSnapshot.data()
};
const itemIndex = list.findIndex(item => item.id ===
newData.id);
if (itemIndex !== -1) {
list[itemIndex] = newData;
} else {
list.push(newData);
}
// do it like thi
if (querySnapshot.docs.length === list.length) {
setSensorsData(list);
console.log(sensorsData);
setLoading(false);
}
});
});
});
}, [currentAccountId, currentShopId]);

push object to array react native

I need to get specific users who have the serviceClientID field in the firestore.
those that do, I insert it into the array and put it in my state chats (setChat).
but the problem is that only one user is entering my state and I have two users with this field.
why is only 1 entering and not 2?
code below:
firebase.auth().onAuthStateChanged(async ({ uid }) => {
const servicesCollection = await firestore()
.collection('Providers')
.doc(uid)
.collection('ServiceHistory')
.get();
servicesCollection.docs.forEach(async item => {
if (item.exists && item.data().serviceClientID) {
const clientsCollection = await firestore()
.collection('Clients')
.doc(item.data().serviceClientID)
.get();
// if (item.data().serviceClientID === clientsCollection.id) {
const values = {
id: clientsCollection.id,
name: clientsCollection.data().name.last,
uid,
};
const arr = [];
arr.push(values);
// }
console.log('arrayay', arr);
setChats(arr);
}
});
});
Cause every loop you empty an array.
You have to get the {arr} out of the function. then you need to push the data inside.
const firebaseFunc = () => {
let arr = [];
firebase.auth().onAuthStateChanged(async ({ uid }) => {
const servicesCollection = await firestore()
.collection('Providers')
.doc(uid)
.collection('ServiceHistory')
.get();
servicesCollection.docs.forEach(async item => {
if (item.exists && item.data().serviceClientID) {
const clientsCollection = await firestore()
.collection('Clients')
.doc(item.data().serviceClientID)
.get();
arr.push({
id: clientsCollection.id,
name: clientsCollection.data().name.last,
uid,
});
});
});
setChats(arr);
console.log('arrayay', arr);
}

implement the onSnapshot function for getting realtime updates in reactjs code

in my case I want to implement the onSnapshot function for getting realtime updates, so here's my sample code it's working now:
db.collection("Cities").onSnapshot((snapshot) => {
snapshot.docs.forEach((doc) => {
console.log(doc.data());
});
});
But now, how can I implement it to the following code
getMyInfo = () => {
db.collection("Cities")
.limit(8)
.get()
.then((docs) => {
if (!docs.empty) {
let AllCities = [];
docs.forEach(function (doc) {
const city = {
id: doc,
...doc.data(),
};
AllCities.push(city);
});
this.setState(
{
cities: AllCities,
},
() => {
this.setState({
isLoaded: true,
});
}
);
}
});
};
Thanks
You are saving all your cities into your state. Use it to add or update the new (or updated) cities.
Maybe you can try something like that :
db.collection("Cities").onSnapshot((snapshot) => {
snapshot.docs.forEach((doc) => {
const updatedCity = doc.data();
const cities = [...this.state.cities];
const index = this.state.cities.findIndex(c => c.id === updatedCity.id);
if (index >= 0) {
cities[index] = updatedCity;
} else {
cities.push(updatedCity);
}
this.setState({ cities });
});
});

Firestore + React.js how to get documents from a collections by filtering from user?

I have three fields for data, by default in the constructor they all setted to all. What ı want to do is making multiple queries on these fields like in mysql. For example: where field1 is apple, field2 is orange and ı do not touch the field 3.(Tumu means "All" by the way.) Here is my code:
class Kurumlar extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: true,
page: 1,
HizmetTuru: "Tumu",
HizmetAlani: "Tumu",
Ucretlendirme: "Tumu"
};
}
handleChange = e => {
this.setState({
[e.target.name]: e.target.value
}, console.log(this.state));
}
componentDidMount() {
const db = firebase.firestore();
let docs = db.collection("Paydaslar")
console.log(this.state)
//docs = db.collection("Paydaslar").where("HizmetTuru", "==", this.state.HizmetTuru);
docs.get()
.then(snapshot => {
let data = [];
snapshot.forEach(doc => {
if (doc.data().isVisible) {
data.push(doc.data());
}
});
this.setState({ data, isLoading: false });
})
.catch(err => {
console.log("Error getting documents", err);
});
}
componentDidUpdate(){
const db = firebase.firestore();
let docs = db.collection("Paydaslar")
if(this.state.HizmetTuru != "Tumu"){docs=db.collection("Paydaslar").where("HizmetTuru", "==", this.state.HizmetTuru)}
if(this.state.HizmetAlani != "Tumu"){docs=db.collection("Paydaslar").where("HizmetAlani", "==", this.state.HizmetAlani)}
if(this.state.Ucretlendirme != "Tumu"){docs=db.collection("Paydaslar").where("Ucretlendirme", "==", this.state.Ucretlendirme)}
docs.get()
.then(snapshot => {
let data = [];
snapshot.forEach(doc => {
if (doc.data().isVisible) {
data.push(doc.data());
}
});
this.setState({ data, isLoading: false });
})
.catch(err => {
console.log("Error getting documents", err);
});
}
By this way if 1 field is setted to a value(different from all(Tumu in the code), other fields do not work.
If I understand correct you want to build a query with multiple possible conditions, depending on what the user selected.
In that case you can use the builder pattern:
const db = firebase.firestore();
let query = db.collection("Paydaslar").collection("Paydaslar")
if(this.state.HizmetTuru != "Tumu") {
query = query.where("HizmetTuru", "==", this.state.HizmetTuru)
}
if(this.state.HizmetAlani != "Tumu") {
query = query.where("HizmetAlani", "==", this.state.HizmetAlani)
}
if(this.state.Ucretlendirme != "Tumu"){
query = query.where("Ucretlendirme", "==", this.state.Ucretlendirme)
}
docs.get()
...
I figured it out just in the if parts, do:
if (this.state.HizmetTuru != "Tumu") { docs = docs.where("HizmetTuru", "==", this.state.HizmetTuru) }
if (this.state.HizmetAlani != "Tumu") { docs = docs.where("HizmetAlani", "==", this.state.HizmetAlani) }
if (this.state.Ucretlendirme != "Tumu") { docs = docs.where("Ucretlendirme", "==", this.state.Ucretlendirme) }

Resources