How to use data as key in Firebase? - javascript

This is my current Firebase database configuration where I want to use username as key and CurrentUser.ID as the value.
I tried to use string interpolation but I got some error.
function updateExistingUserRoot(username) {
const { currentUser } = firebase.auth();
return (dispatch) => {
firebase.database().ref(`/ExistingUser`).push({
`${username}`: currentUser.uid
})
}
}
I understand firebase generates an unique key every time data is being pushed but I would like to stay with the current configuration.
Update 1
I have changed to using set but the error persists.
function updateExistingUserRoot(username) {
const { currentUser } = firebase.auth();
firebase.database().ref(`/ExistingUser`).set({
`${username}`: currentUser.uid
});
}
The error: expected property assignment.

For the configuration you want, you should rather be using set or update methods to save or update your data.
firebase.database().ref(`/ExistingUser`).set({
`${username}`: currentUser.uid
})
This way, your data gets saved in the username node which will be mapped with the user's uid.
Hope that helps!

If you want to create a user with a specific key, you should remove the push method (that creates a unique key) and use something like:
firebase.database().ref(`/ExistingUser` + userKey).set({
username: value...
});
Everything in Firebase is an url.
https://testxxx.firebaseio.com/xxx/ExistingUser
If you want to create a user with a key of KEY1 as a child at this location you would have:
https://testxxx.firebaseio.com/xxx/ExistingUser/KEY1

The answer given by the two gentlemen are correct but I had to tweaked a little bit to get it working.
Here's the code
firebase.database().ref(`/ExistingUser/${username}`).set({
userID: currentUser.uid
}).then(() => console.log('Set existing user done'))
.catch((error) => console.log(error.message))

Related

Bulk Update using Batched Write of Firebase with conditions (using WHERE function)

The main goal of my system is to update the name of the user who posted on my forum if the authenticated user change or rename his or her account name.
The whole process is error-free but unfortunately, the other user who posted in the forum also updated their name.
So this is the output:
I try the following:
I use the WHERE function in Firebase to filter the post made by the user (log in user itself). I dont know why the whole process is failed.
This is the snippet code.
async updateAll(username) {
const batch = this.afs.firestore.batch();
// cUser is the USER ID
const userRef = this.afs
.collection('post', (ref) => ref.where('postedById', '==', this.cUser))
.ref.get();
(await userRef).forEach((element) => {
batch.update(element.ref, {
postedBy: username,
});
});
return batch.commit();
}
You end your query with .ref.get(). The .ref in there, actually returns the collection on which you run the query, so you end up loading the entire post collection.
You'll want to subscribe to snapshotChanges instead, or just use the regular JavaScript SDK to accomplish this (as you're not accessing the UI directly, I typically find that easier):
const userRef = firebase.firestore()
.collection('post').where('postedById', '==', this.cUser).get();
(await userRef).forEach((element) => {
batch.update(element.ref, {
postedBy: username,
});
});

How can a user's displayName be added to a Firestore database collection entry?

I am setting up a simple webpage with Firebase Authentication and a Firestore database which takes user inputs from a form, adds the inputs as a collection document in Firestore, and then also outputs the whole collection. Each document in the collection has two fields, the Name and the Body of the document. The goal is to allow users to make posts on the website using the input form. Everything I described is working, but now I would like to display the user.displayName with the post, to show who exactly created the user input, and that's what I can't figure out how to do. Here's the relevant code, from the script.js of the website:
const createForm = document.querySelector('#create-form');
createForm.addEventListener('submit', (e) => {
e.preventDefault();
db.collection('forumposts').add({
Body: createForm['body'].value,
//the line below is what I cannot figure out how to set up
Name: string(user.displayName)
}).then(() => {
//reset the form
createForm.reset();
}).catch(err => {
console.log(err.message)
})
});
I'm still learning about JavaScript, so I apologize if I am missing something obvious. I know the user's displayName (which is collected upon sign up) is being collected properly, as I can log it to the console and it shows up correctly. I just cannot figure out how to then add it as a field in this database collection input. I have tried searching here on SO for related questions, but am only getting questions related to how the user can add a display name on sign-up. I already have the display name, I just need to input it into the database. Any help would be greatly appreciated!
Where is the "user" defined? That could be null if no user is logged in so it's better to check for the user.
const createForm = document.querySelector('#create-form');
createForm.addEventListener('submit', (e) => {
e.preventDefault();
const user = firebase.auth().currentUser
if (user) {
db.collection('forumposts').add({
Body: createForm['body'].value,
Name: user.displayName || "No username"
}).then(() => {
//reset the form
createForm.reset();
}).catch(err => {
console.log(err.message)
})
} else {
console.log("NO user logged in")
}
});
You don't need the String() constructor. If displayName is defined it'll be a string. You can use if (user.displayName) before adding the post to check if user has a display name.
It's String(), not string(). As long as displayName is a property of user, it will be added to the database.

How to (using React JS web) and Firestore, can you find out when a chatRoom (on the Firestore Database) receives new messages?

I am trying to build an app using FireStore and React JS (Web)
My Firestore database basically has:
A collection of ChatRooms ChatRooms
Every chat-room has many messages which is a subcollection, for example:
this.db.collection("ChatRooms").doc(phone-number-here).collection("messages")
Also, every chat-room has some client info like first-name, last-name etc, and one that's very important:
lastVisited which is a timestamp (or firestamp whatever)
I figured I would put a React Hook that updates every second the lastVisited field, which means to try to record as accurately as possible on Firestore the last time I left a chat-room.
Based on that, I want to retrieve all the messages for every customer (chat-room) that came in after the last visit,
=> lastVisited field. :)
And show a notification.
I have tried from .onSnapshot listener on the messages subcollection, and a combination of Firestore Transactions but I haven't been lucky. My app is buggy and it keeps showing two, then one, then nothing, back to two, etc, and I am suffering much.
Here's my code!
Please I appreciate ANY help!!!
unread_messages = currentUser => {
const chatRoomsQuery = this.db.collection("ChatRooms");
// const messagesQuery = this.db.collection("ChatRooms");
return chatRoomsQuery.get().then(snapshot => {
return snapshot.forEach(chatRoom => {
const mess = chatRoomsQuery
.doc(chatRoom.id)
.collection("messages")
.where("from", "==", chatRoom.id)
.orderBy("firestamp", "desc")
.limit(5);
// the limit of the messages could change to 10 on production
return mess.onSnapshot(snapshot => {
console.log("snapshot SIZE: ", snapshot.size);
return snapshot.forEach(message => {
// console.log(message.data());
const chatRef = this.db
.collection("ChatRooms")
.doc(message.data().from);
// run transaction
return this.db
.runTransaction(transaction => {
return transaction.get(chatRef).then(doc => {
// console.log("currentUser: ", currentUser);
// console.log("doc: ", doc.data());
if (!doc.exists) return;
if (
currentUser !== null &&
message.data().from === currentUser.phone
) {
// the update it
transaction.update(chatRef, {
unread_messages: []
});
}
// else
else if (
new Date(message.data().timestamp).getTime() >
new Date(doc.data().lastVisited).getTime()
) {
console.log("THIS IS/ARE THE ONES:", message.data());
// newMessages.push(message.data().customer_response);
// the update it
transaction.update(chatRef, {
unread_messages: Array.from(
new Set([
...doc.data().unread_messages,
message.data().customer_response
])
)
});
}
});
})
.then(function() {
console.log("Transaction successfully committed!");
})
.catch(function(error) {
console.log("Transaction failed: ", error);
});
});
});
});
});
};
Searching about it, it seems that the best option for you to achieve that comparison, would be to convert your timestamps in milliseconds, using the method toMillis(). This way, you should be able to compare the results better and easier - more information on the method can be found in the official documentation here - of the timestamps of last message and last access.
I believe this would be your best option as it's mentioned in this Community post here, that this would be the only solution for comparing timestamps on Firestore - there is a method called isEqual(), but it doesn't make sense for your use case.
I would recommend you to give it a try using this to compare the timestamps for your application. Besides that, there is another question from the Community - accessible here: How to compare firebase timestamps? - where the user has a similar use cases and purpose as yours, that I believe might help you with some ideas and thoughts as well.
Let me know if the information helped you!

React + Firebase saving issue. Why this Hash?

Im saving my data to database, using React, like this:
export const matchesInitialCreate = (user, matches) => {
return (dispatch) => {
firebaseApp.database().ref(`/users/${user}/matches`)
.push(matches)
.then(() => {
dispatch({ type: MATCHES_INITIAL_CREATE });
});
};
};
My matches entity is a simple json with some data, divided into
matches:{ groups: {...}, knockout {...}}}
Everything looks fine, but when I push it to firebase, it is saved with a hash. Like this:
users/user/matches/CRAZY_HASH/matches/groups
But I want that it saves like this:
users/user/matches/groups
What Im doing wrong?
There are different ways to save data to Firebase Realtime Database.
Push: generates a unique key at the specified reference, and writes the given data under this new child
Set: save data to a specified reference, replacing any existing data at that path
Update: updates lower-level child values of a specified reference
The reason why you see a crazy hash is you are using the push method. If you want to set the data directly under users/{user}/matches/groups, you must use either set or update.
// Will override everything
firebaseApp.database().ref(`/users/${user}/matches`).set(matches)
// Will update specific children
firebaseApp.database().ref(`/users/${user}/matches`).update(matches)

#ionic change the data key in firebase

I'm trying to update/add data on firebase. I used the Facebook login and I want to use the UserID as a key for the new data aded.
(check pict below)
The userID that I want to use it:
I want to replace that key with the userID:
fblogin(){
this.facebook.login(['email'])
.then(res=> {
const fc = firebase.auth.FacebookAuthProvider.credential(res.authResponse.accessToken);
firebase.auth().signInWithCredential(fc)
.then(fs => {
this.facebook.api('me?fields=id,name,email,first_name,picture.width(720).height(720).as(picture_large)', []).then(profile => {
this.newuser = {name: profile['first_name'] ,email: profile['email'],picture: profile['picture_large']['data']['url'],phone:''}
this.navCtrl.push(HomePage);
console.log(fs.uid);
this.db.list('/users/'+ fs.uid).update(this.newuser);
});
I got this error in compilation:
supplied parameters do not matchany signature of call target
In this line: this.db.list('/users/'+ fs.uid).update(this.newuser);
Any help?
The FB error looks correct. You cant update on the uid as the user has been saved with a unique FB id
You do not show the code that created the users record in the database, but what i think you want to do is set and object when you first save the users record. However this could be an issue because the user could be saved before the return of the uid. I cant tell with your code snippet. Regardless, I will write the code that i think will work if the users/ record is created at the time that of registration.
The service
async signupUser(email: string, password: string) {
try {
const result = await this.afA.auth.createUserWithEmailAndPassword(email, password);
return result;
} catch (err) {
console.log('error', err);
}
}
So this initially creates a user without facebook, The key here is that the users FB uid was created and is held in the returned result
The component
this.authData.signupUser(email,password).then(userData => {
console.log(userData) // <- this is result
}
Then we create a record in FB with the uid returned
this.db.object(`users/${userData.uid}/`).set(data);
.set(data) is whatever data you want to save in the users/uid namespace.
So basically you need to create that user table with its uid namespace when the user first registers. Then you can update the user with the uid returned from the facebook fs.uid
With your current code you could find the user based on the email ( because the email should be unique to all users) and then update ...
with lodash is it just
let foundUser = find(this.db.list('users'),{ 'email' : fs.email }
// and then update based on the object key
this.db.list('/users/'+ Object.keys(foundUser)).update(this.newuser);
i fixed the problem by using:
this.db.object('/users/'+ fs.uid).update(this.newuser);
instead of :
this.db.list('/users/'+ fs.uid).update(this.newuser);
And it works correctly !
Thanks all for help.

Categories

Resources