Realtime database query and react native - javascript

I'm quite new to performing firebase realtime database queries and react native. I have a list of users in my realtime database and some of the users have a list of properties as shown below. I would like to obtain these properties as well as the users of the properties and place it into an array using react native. I'm not to sure how to do this.
This is what I have so far:
database().ref(`users/`).once(`value`, snapshot =>{
snapshot.forEach(function(childSnapshot){
if(childSnapshot.val().properties != null) {
}
});
I would like the error to be displayed as:
[{uid1,property1}, {uid1,property2}, {uid2,property1}, {uid2,property2}, {uid2,property3},...., {uidX,propertyX}]
})

I find that in cases like this, it really helps to give your variables good names:
database().ref(`users/`).once(`value`, snapshot =>{
let properties = [];
snapshot.forEach((userSnapshot) => {
if (userSnapshot.hasChild("properties")) {
userSnapshot.child("properties").forEach((propertySnapshot) => {
properties.push({
uid: userSnapshot.key,
property: propertySnapshot.val()
})
})
}
});
console.log(properties);
});

Related

How to read firestore data in react native?

Hello I am new to react native and particullary firebase. I've been watching tutorial about using firebase with react native and i read the react native firebase documentation but i am stuck. I have data in my firestore data base, in my collection called user but I am not able to read, to get the data from it. Here is my firestore database :
and here is how I tried to get the data in my component :
const Profile = ({navigation, ...props}) => {
async function getUserData () {
const userCollection = await await firebase.firestore().collection('users').doc(firebase.auth().currentUser.uid).get()
return userCollection
}
console.log('🐲' + getUserData())
this return me that : [object Object]
I also tried this, (it was how it was done in the instagram clone tutorial of Adrian Twarog) :
const Profile = ({navigation, ...props}) => {
function getUserDataFirstTry() {
firebase.firestore()
.collection("users")
.doc(firebase.auth().currentUser.uid)
.get()
.then((snapchot) => {
if(snapchot.exists){
console.log('🦜' + snapchot.data())
} else {
console.log('merde ca marche pas')
}
})
}
console.log('🐲🐲' + getUserDataFirstTry())
But I get the same result in my console : [object Object]
I tried to put my function in a useEffect hook but this changes nothing.
Can you tell me what I am doing wrong ? (if possible in the second example because it's realtime changes). Thanks.
As Nicholas commented, since you're concatenating snapchot.data() to a string, you get the string representation of that object, which is pretty useless.
To log a specific field from the data:
console.log('🦜' + snapchot.data().userName)
To log all fields from the data in a more useful format:
console.log('🦜' + JSON.stringify(snapchot.data()))
Note: the proper spelling is snapshot (not snapchot), but I kept your original spelling here for ease of copy/paste.

How to listen firebase real-time changes into Reactjs?

I am creating a real-time chat application using firebase and React js. I create a const functions = require('firebase-functions');
called "chats" inside the firebase. This collection contains unique room_ID(a combination of sender and receiver) and that document again contains subcollections called "messages". Each collection inside the message has infomation like message, time, sender_id, and read status.
Now, every time, when I receive a new message into the chat list I have to update the conversation. I use componentDidMount() method of Reactjs and write below code:
firestore.collection('chats').doc("b7EuhNpdzXUlxhSgDkn2a6oReTl1_OZbrlH8FjmVFqSAtAc0A6TUHS3I3").collection("messages")
.onSnapshot(querySnapshot => {
console.log("querySnapshot", querySnapshot)
querySnapshot.docChanges().forEach(change => {
console.log("change", change)
if (change.type === 'added') {
this.setState({messages : [...this.state.messages, change.doc.data()]});
console.log('New city: ', change.doc.data());
}
if (change.type === 'modified') {
console.log('Modified city: ', change.doc.data());
}
if (change.type === 'removed') {
console.log('Removed city: ', change.doc.data());
}
});
});
You can see here that, It will only work for a single room(b7EuhNpdzXUlxhSgDkn2a6oReTl1_OZbrlH8FjmVFqSAtAc0A6TUHS3I3). I want to write query in such a way that it will listen to the message for each contact. For that, I have to remove the restriction of specific doc.
Please help me.
Thank you in advance.
Here is the structure of Firebase database.
Look into the documentation for CollectionGroups - set your listener to the .collectionGroup("messages") - you will have to process through the changes for all of the different "chats" documents. (HINT: each returned messages DocRef includes the refPath field - which you can trivially parse to find the path to the "parent" chat document)
I believe a few better approaches to fetch the data you want would be to either:
Restructure your Firestore to have only a messages collection, like the following example structure:
messages collection
uid
receiverUserId
senderUserId
msg
read
time
With this approach you could filter the documents you are watching, for example documents received by the currently authenticated user from multiple users, by doing something like this:
firestore.collection("messages")
.where("receiverUserId", "==", authUid)
.onSnapshot(function(querySnapshot) {
//do whatever
});
Create multiple listeners, one for each chats document, to watch it's subsequent messages subcollection. So you could do something like this untested code:
firestore.collection('chats').get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
var eachChatRef = firestore.collection('chats').doc(doc.documentID)
var messagesRef = eachChatRef.collection("messages");
messagesRef.onSnapshot(function(snapshot) {
snapshot.docChanges().forEach(function(messageDoc) {
// Do whatever
});
});
});
});
To extend to #LeadDreamer answer, this worked for me to listen to changes in all documents in a collection using collectionGroup:
const unsub = () =>
onSnapshot(collectionGroup(db, "reservations"), (doc) => {
doc.docs.forEach((d) => {
console.log(d.data());
});
});

How to hit/consume post and get api in React Native with Ignite Bowser 2 Boilerplate. (Mobx state stree, type script)

I am new to React Native, please provide some Github link or your own code for reference. Consider me as a beginner in RN.
I found very less open support for RN, Mobx State tree, Ignite and all, so not just post and get API reference, if you find anything helpful related to these above-mentioned topics, Feel free to share.
Thanks in advance.
Mobx State Tree, With Ignite Bowler you would have api.ts file where you can specify API calls.
async getUser(userToken: string): Promise<Types.GetUserResult> {
// make the api call
const response: ApiResponse<any> = await this.apisauce.post(`api/v1/sales/login?authCode=${userToken}`)
if (!response.ok) {
const problem = getGeneralApiProblem(response)
if (problem) return problem
}
// transform the data into the format we are expecting
try {
try {
const rawUser = response.data
console.log('rawUser'+ rawUser)
const user: UserSnapshot = convertRawUserToUserStore(rawUser)
return { kind: "ok", user }
console.log({ user })
} catch (e) {
__DEV__ && console.tron.log(e.message)
return { kind: "bad-data" }
}
} catch {
return { kind: "bad-data" }
}
}
Consider, we will be getting user data from this API call,
you can notice that there is UserSnapshot which belongs to User Model, Snapshot will save the data automatically, you don't need Aysnc storage to save or retrieve data.

Can't get object key in firebase

Problem: I am making an app with Firebase and React Native where users can post, and then other users can comment on posts. To do the comments, I need to grab the key of the content of a post. I tried using the child.getKey() function, but that gave me an error.
child.getKey is not a function. (In 'child.getKey()', 'child.getKey' is undefined)
I would really love some help getting the key. Thank you!
Code
getItems(){
var items = [];
var query = ref.orderByKey();
query.once ('value', (snap) => {
snap.forEach ( (child) => {
items.push({
content: child.val().content,
key: child.getKey()
});
});
items.reverse();
}).then(() => {
this.setState({firebaseItems: items});
});
}
Firebase layout
Posts:
-Kier498dma39md:
content: 'This is an example post. The numbers above me are an example of the random key I am trying to get.'
So, I did some research, and eventually found out all I needed to do was use key: child.key

Firebase React Binding

I'm somewhat new to React, and using the re-base library to work with Firebase.
I'm currently trying to render a table, but because of the way my data is structured in firebase, I need to get a list of keys from two locations- the first one being a list of user keys that are a member of a team, and the second being the full user information.
The team node is structured like this: /teams/team_id/userkeys, and the user info is stored like this: /Users/userkey/{email, name, etc.}
My table consists of two react components: a table component and a row component.
My table component has props teamid passed to it, and I'm using re-base's bindToState functionality to get the associated user keys in componentWillMount(). Then, I use bindToState again to get the full user node, like so:
componentWillMount() {
this.ref = base.bindToState(`/teams/${this.props.data}/members`, {
context: this,
state: 'members',
asArray: true,
then() {
this.secondref = base.bindToState('/Users', {
context: this,
state: 'users',
asArray: true,
then() {
let membersKeys = this.state.members.map(function(item) {
return item.key;
});
let usersKeys = this.state.members.map(function(item) {
return item.key;
});
let onlyCorrectMembersKeys = intersection(membersKeys, usersKeys);
this.setState({
loading: false
});
}
});
}
});
}
As you can see, I create membersKeys and usersKeys and then use underscore.js's intersection function to get all the member keys that are in my users node (note: I do this because there are some cases where a user will be a member of a team, but not be under /Users).
The part I'm struggling with is adding an additional rebase call to create the full members array (ie. the user data from /Users for the keys in onlyCorrectMembersKeys.
Edit: I've tried
let allKeys = [];
onlyCorrectMembersKeys.forEach(function(element) {
base.fetch(`/Users/${element}`, {
asArray: true,
then(data) {
allKeys.prototype.concat(data);
}
});
});
But I'm receiving the error Error: REBASE: The options argument must contain a context property of type object. Instead, got undefined
I'm assuming that's because onlyCorrectMembersKeys hasn't been fully computed yet, but I'm struggling with how to figure out the best way to solve this..
For anyone dealing with this issue as well, I seemed to have found (somewhat) of a solution:
onlyCorrectMembersKeys.map(function(item) {
base.fetch(`/Users/${item}`, {
context: this,
asObject: true,
then(data) {
if (data) {
allKeyss.push({item,data});
this.setState({allKeys: allKeyss});
}
this.setState({loading: false});
},
onFailure(err) {
console.log(err);
this.setState({loading: false});
}
})
}, this);
}
This works fine, but when users and members state is updated, it doesn't update the allkeys state. I'm sure this is just due to my level of react knowledge, so when I figure that out I'll post the solution.
Edit: using listenTo instead of bindToState is the correct approach as bindToState's callback is only fired once.

Categories