How to display some data from firebase in react-native - firebase

I want to display some data from firebase, the problem is that I don't know how to do this after trying many things.
My firebase datbase looks like this:
Now I want to put this data into a calender, so I want only the date from one userID. So I can get only one date, and then use it.
How can I do this?
I now use this:
componentDidMount() {
let userId = firebase.auth().currentUser.uid;
firebase.database().ref('poolog/' + userId ).on('value', (snapshot) => {
this.setState({abc: snapshot.val().childData});
let data = snapshot.val();
let datums = Object.values(data);
this.setState({datums});
});
};
And then I want to render it:
render(){
return(
<View>
<Text>{
this.state.datums
}</Text>
</View>
);
}

basically this way i put every single day of an user in an array so you can access any day.And then you can access each day by an index.
componentDidMount(){
var days = []
firebase.database().ref('poolog/' + userId ).once('value', (snap) => {
snap.forEach((data)=>{
days.push({
day:data.key,
availableHours:data.val()
})
})
console.log(days)
//this.setState({datums:days})
})
}

Related

How to combine two Redux Firebase Cloud Firestore queries?

I have two redux queries that pull posts from my Firebase Firestore. The first successfully displays all of the posts of the people I'm following:
export function fetchUsersFollowingPosts(uid) {
return ((dispatch, getState) => {
firebase.firestore()
.collection("posts")
.doc(uid)
.collection("userPosts")
.orderBy("creation", "asc")
.get()
.then((snapshot) => {
const uid = snapshot.query.EP.path.segments[1];
const user = getState().usersState.users.find(el => el.uid === uid);
let posts = snapshot.docs.map(doc => {
const data = doc.data();
const id = doc.id;
return { id, ...data, user }
})
for (let i = 0; i < posts.length; i++) {
dispatch(fetchUsersFollowingLikes(uid, posts[i].id))
}
dispatch({ type: USERS_POSTS_STATE_CHANGE, posts, uid })
})
})
}
The second shows all of my own posts.
export function fetchUserPosts() {
return ((dispatch) => {
firebase.firestore()
.collection("posts")
.doc(firebase.auth().currentUser.uid)
.collection("userPosts")
.orderBy("creation", "desc")
.get()
.then((snapshot) => {
let posts = snapshot.docs.map(doc => {
const data = doc.data();
const id = doc.id;
return { id, ...data }
})
dispatch({ type: USER_POSTS_STATE_CHANGE, posts })
})
})
}
Here's where I currently list the users from the people I follow. But how do I combine them so I can show both my posts and those of the people that I'm following in a single FlatList?
function Feed(props) {
useStatusBar('dark-content');
const [posts, setPosts] = useState([]);
const [refreshing, setRefreshing] = useState(false)
useEffect(() => {
if (props.usersFollowingLoaded == props.following.length && props.following.length !== 0) {
props.feed.sort(function (x, y) {
return y.creation.toDate() - x.creation.toDate();
})
setPosts(props.feed);
setRefreshing(false)
}
}, [props.usersFollowingLoaded, props.feed])
return (
<View style={styles.background}>
{posts.length > 0 ?
<View style={styles.containerGallery}>
<FlatList
refreshControl={
<RefreshControl
refreshing={refreshing}
tintColor="white"
onRefresh={() => {
setRefreshing(true);
props.reload()
}}
/>
}
showsVerticalScrollIndicator={false}
numColumns={1}
horizontal={false}
data={posts}
renderItem={({ item }) => (
<View style={styles.containerImage}>
<Card title={item.title} onPress={() => props.navigation.navigate(routes.GOOD_STUFF_DETAIL, { item: item, postId: item.id, uid: item.user.uid, user: item.user,})} showLike={true} author={"Recommended by " + item.user.name} likeItem={item} likeCount={item.likesCount} icon={categories.categories[item.categoryID].icon} timeStamp={timeDifference(new Date(), item.creation.toDate())}/>
</View>
)}
/>
</View>
: <NothingHere title="Follow friends" text="To see their Good Stuff here" icon="search" color="white"/> }
</View>
)
}
const mapStateToProps = (store) => ({
currentUser: store.userState.currentUser,
following: store.userState.following,
feed: store.usersState.feed,
usersFollowingLoaded: store.usersState.usersFollowingLoaded,
})
const mapDispatchProps = (dispatch) => bindActionCreators({ reload }, dispatch);
export default connect(mapStateToProps, mapDispatchProps)(Feed);
Below is my data structure:
Thanks for reading!
Maybe I misunderstood the database structure but AFAIK it doesn't seem possible to combine both queries. From what I see of the database structure you want to retrieve the posts of userB where you (userA) gave a "like". In order to get that information you scan across the path posts/{userUID}/userPosts/{docId}/likes. Given the queries scan different collection ranges I don't see a way to mix them.
Separately, let's assume for the sake of the argument that you already have a list containing the user UIDs of the people you follow. Then, the Firestore query feature that gets closer to the desired behavior are Collection Group queries. Having in mind the structure of the database:
posts
uid1
userPosts
doc1
doc2
uid2
userPosts
docX
docY
Essentially, collection group queries are a way to simultaneously query across all userPosts collections at once. If each document were to have the author ID as a field you would be able to do something like this:
db.collectionGroup("userPosts").where("uid", "in", ListOfFollowedUsers)
This won't totally solve the problem because the in operator clause is limited to 10 values, so you may apply it at most for 10 followed users.
Overall I would suggest to keep the queries separated and merge them in the application code.
Based on your data, and knowing for a fact how limited queries on Firestore are, you need to do that merge on the client.
What I would do is to keep the list on redux and handle the merge on the reducer. You just need to listen to both actions and then merge them as an array on your app.
If you want to avoid the user seeing partial data (eg, you show your own posts and then another refresh just adds your followers post thus the UI will change) you might want to keep two flags (booleans) while you are loading data and show a spinner if both lists haven't been loaded.
Unless you want to refactor your code, then a lot of merging happens on the client.
Also, side node, I would NOT dispatch something on a for loop like you are doing on the first one, because if that triggers a firestore request, then it might get expensive real fast.

Is there a correct way to add same data documents into two different collections in firestore?

Following code inserts data into the 'doctors' collection in firestore. But I want to add the same data records into another collection named 'next' in the same firestore database simultaneously.
service.ts
create_Newdoctor(Record){
return this.firestore.collection('doctors').add(Record);
}
component.ts
CreateRecord(docForm: NgForm){
let Record = {};
Record['fullName']=this.fullName;
Record['email']=this.email;
Record['gender']=this.gender;
Record['role']="doctor";
this.DoctorService.create_Newdoctor(Record).then(res=> {
this.fullName="";
this.email="";
this.gender="";
console.log(res);
this.message = "New doctor added";
}).catch(error=>{
console.log(error);
});
}
Can you please tell me a way to do this.Thank you in advance.
const collections = ["doctors", "next"];
create_Newdoctor(Record, collections) {
const promises = collections.map(collectionName =>
this.firebase.collection(collectionName).add(Record)
);
return Promise.all(promises);
}

Chaining Firebase Firestore documents/collections

So, I have a Firestore database group like so.
companies > acme-industries > items > []
OR
collection > document > collection > document
Would it be better to just store all items inside a base collection and then add a string value to each item that defines what company it goes too? Then just query the items collection for all items linked to that company?
I am trying to retrieve the items and run them through a forEach in my firebase function. I have tried two different approaches and watched multiple videos and still am not getting results.
First Attempt Code Block
This resulted in a 500 Server Error with no explanation returned.
const itemQuerySnapshot = db.collection('companies').doc(data.userData.company).collection('items').get();
const items: any = [];
itemQuerySnapshot.forEach((doc:any) => {
console.log('doc', doc.data());
items.push({
id: doc.id,
data: doc.data()
});
});
response.json(items);
Second Attempt Code Block
This resulted in the No Such Documents! being returned
const itemRef = db.collection('companies').doc(data.userData.company).collection('items');
itemRef.get().then((doc:any) => {
if(!doc.exists) {
response.send('No such documents!');
} else {
response.send('Document Data: '+ doc.data());
}
}).catch((err:any) => {
response.status(500).send(err);
});
I am expecting something like an array of all the items to be returned from this call. I'm completely new to Firebase Firestore, what am I missing here?
UPDATE
I replaced my code with a third attempt code block and I got success with the console.log(doc.data()). However, the items object still returns empty. Is this because it's returning before the for each is done? If so, how would you prevent that to ensure every item that should be returned is?
const items: any = [];
const userRef = db.collection("companies").doc(data.userData.company);
const itemsRef = userRef.collection("items");
itemsRef
.get()
.then((snapshot: any) => {
snapshot.forEach((doc: any) => {
console.log(doc.data());
items.push({
id: doc.id,
data: doc.data()
});
});
})
.catch((err: any) => {
response.status(500).send(err);
});
response.json(items);
How would you add one more document into the mix? Say you want to get a single item. How would you do that? The following always results in Item does not exist being returned from my function.
const companyRef = db.collection('companies').doc(data.userData.company);
const itemRef = companyRef.collection('items');
const item = itemRef.where('number', '==', itemSku).get();
I must be doing something incredibly wrong here because all the videos are telling me it's incredibly easy to fetch data from Firestore. But I have yet to see that.
get returns a Promise , the callback of then function will be called once the data ready from firestore .
the line response.json(items); will be called before the items array collected correctly.
you need to move this line inside the then callback
checkout this :
.then((snapshot: any) => {
snapshot.forEach((doc: any) => {
console.log(doc.data());
items.push({
id: doc.id,
data: doc.data()
});
});
response.json(items); //items ARRAY IS READY , YOU CAN SEND YOUR RESPONSE HERE
})

How to reference a child of a child

I am currently using Firebase and Dialogflow. I wish to take in 2 parameters,courses and facilities Location, and access the information of the child of a child, however I am not sure how to do so. I will attach an image of the database for reference.
Firebase Database:
else if (action === 'course_day') { //For courses
const product = request.body.queryResult.parameters.courses.trim();
const product = request.body.queryResult.parameters.facilitiesLocation.trim();
const ref = db.ref(`courseday/${product.toLowerCase()}`);
ref.once('value').then((snapshot) => {
const result = snapshot.val();
if (result === null) {
response.json({
fulfillmentText: `We do not have such a course.Simply say, for example, 'What day is Chinese Calligraphy on?'!`
});
return;
}
response.json({
fulfillmentText: `${product} lessons are on ${result.day}`,
source: action
});
}).catch((err) => {
response.json({
fulfillmentText: `I don't know what is it`
});
});
On calling the 'once' function in the 'datasnapshot' you will receive the whole underlying data as a JSON. So all you have to do is move into this JSON and get the required value.
In this case, let's say your ref is pointing to 'test' branch of your db then when you call ref.once you will receive everything under that branch.
Hope this helps

Redux Thunk Firebase - fetch arrays

I'm building a react native app with redux, react-redux, redux-thunk, and using firebase as a backend.
My database is denormalized, so I've to fetch keys in a firebase reference and for each key I need to fetch data from another reference.
Using firebase .once('value') I got something like this:
const fetchPosts = ( uid ) => {
return ( dispatch ) => {
dispatch(postsIsFetching())
const userPostsRef = firebase.database().ref('users/' + uid + '/myposts')
var keys = []
//
userPostsRef.once('value').then(snap => {
snap.forEach(post => keys.push(post.key))
}).then(() => {
keys.forEach(key => {
const postRef = firebase.database().ref('posts/' + key )
postRef.once('value').then(snap => {
var newPost = {
title: snap.val().title,
user: snap.val().user
}
dispatch(setPost(newPost))
})
})
}
}
But that's not realtime updating, cause the .once() method read data once only.
The .on() method doesn't return a Promise, so how could I fix that?
What's the best pattern to fetch data with redux-thunk and a denormalized firebase database?
Thanks guys
Put the code you'd normally put in a .then() inside the .on() callback. This way, every time the data refreshes, your setPost action will be dispatched.
For example:
...
postRef.on('value', snap => {
var newPost = {
title: snap.val().title,
user: snap.val().user
}
dispatch(setPost(newPost))
});
You probably want to hold on to that database reference so that you can stop listening later.

Resources