Reputation: 946
I migrated from firebase Realtime Database to Cloud firestore in one of my ReactJS projects. And I am fairly new to Firestore.
Here's what I need. Consider that I have details of items stored in a collection 'Items'.
In Realtime database, I just had to do this to get the data and store it in the state:
database.ref('Items').once('value', (snapshot) => {
this.setState({items: snapshot.val()})
})
snapshot.val()
returns all the objects in Items as a single object containing them. That makes it easy for me to render them in a table with Object.keys(this.state.items).map()
This is not the case with Firestore. Firestore returns an object that can only retrieve the data in the child only by iterating through each one of them.
So the best I could come up with was:
db.collection('Items').get().then(gotData)
gotData = (snapshot) => {
snapshot.forEach((item) => {
const item = {[item.id]: item.data()}
this.setState(previousState => ({
items : {...previousState.items, ...item}
}))
})
}
The problem with the above solution is that the state will get updated a number of times equal to the number of items in the collection. So I wonder if there is a better way to do it.
Upvotes: 1
Views: 5544
Reputation: 7324
Almost there, you just want to put the empty object outside the iteration like so...
db.collection('Items').get().then(snap => {
const items = {}
snap.forEach(item => {
items[item.id] = item.data()
})
this.setState({items})
}
Or you could just map it, which I find easier to think about.
db
.collection('Items')
.get()
.then(collection => {
const items = collection.docs.map(item => {[item.id]: item.data()})
this.setState({ items })
})
Or you can use reduce to return an object containing all the items.
db
.collection('Items')
.get()
.then((collection) => {
const items = collection.docs.reduce((res, item) => ({...res, [item.id]: item.data()}), {});
this.setState({items})
})
Upvotes: 5