Save user info into database just after registration in Firebase - reactjs

I am trying to save a newly created user's info into Firestore using the uid as the document id. The problem I encounter comes after the creation of the user, in order to save his information into the Firestore collection after creation.
Here is what I have already tried:
const usersRef = firebase.firestore().collection('Users');
firebase.auth().createUserWithEmailAndPassword(values.email, values.password).then(function(user){
usersRef.doc(`${user.uid}`).set({
firstName: values.firstName,
lastName: values.lastName,
username: values.username,
uid: user.uid
})
}).catch(function(error){
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// [START_EXCLUDE]
if (errorCode == 'auth/weak-password') {
alert('The password is too weak.');
} else {
alert(errorMessage);
}
console.log(error);
// [END_EXCLUDE]
});
The code is expected to save the user's info after creation, but it causes the following error :
The collection document ID cannot be undefined or so

The method you're using using returns Promise<UserCredential>. Your code should be:
const usersRef = firebase
.firestore()
.collection('Users');
firebase
.auth()
.createUserWithEmailAndPassword(values.email, values.password)
.then(function(userCredential) {
usersRef
.doc(`${userCredential.user.uid}`)
.set({
firstName: values.firstName,
lastName: values.lastName,
username: values.username,
uid: userCredential.user.uid
})
...

Related

How do I fetch a specific result from mongodb

I'm still new to reactjs and mongodb.I am trying to fetch a single record of user and display it on the page. But so far I got no output. I want the page to immediately display the result on load
This is my profile.js:
componentDidMount() {
const user = localStorage.getItem('user')
const userObject = {
username: localStorage.getItem('user'),
};
axios.post('http://localhost:4000/users/getUser', userObject)
.then((res) => {
console.log("hi"+res.data)
const userinfo = res.data
this.setState({
name: userinfo.name,
username: res.username,
email: res.email,
password: res.password,
company: res.company,
position: res.position
})
})
.catch(function (error) {
console.log(error);
})
}
and this is my backend(user.js):
let mongoose = require('mongoose'),
express = require('express'),
router = express.Router(),
user = require('../models/user-schema');
router.post('/getUser', async (req, res) => {
console.log(req.body.username)
const User = await user.find({ name: req.body.username })
if (!User) {
return { status: 'error', error: 'Invalid Login' }
}else {
return res.json({
status: 'ok',
name: User.name,
username: User.username,
email: User.email,
company:User.company,
position: User.position,
level: User.userLevel
})
}
})
user.find({ name: req.body.username }) is going to return an array. So in the code below, all those fields such User.name , User.username, User.email etc are going to be undefined since User = [{name:xxx,username:xxx }]
res.json({
status: 'ok',
name: User.name, // undefined
username: User.username, // undefined
email: User.email, // undefined
company:User.company, // undefined
position: User.position,// undefined
level: User.userLevel // undefined
})
You should use user.findOne({ name: req.body.username }) which will return a single object and then you can access the properties.
Additionally (Personal preference) , one might have multiple users with the same username. To make sure you're retrieving the correct docuemnt, rather use findById().
Instead of this find({}) you can use findOne({}) cause find({}) going to return an array but your are expecting an object that the the problem
Use findOne() instead of find() method, find() method returns an array of objects and findOne() method return a single particular object.
const User = await user.findOne({ name: req.body.username })
and you can pass specific filed which you want to get like
let User = await user.findOne({ name: req.body.username },{username:1, email:1, company:1, position:1, level:1});
if(!User){
return res.status(404).json({ status: 'error', error: 'Invalid Login' });
} else {
return res.status(404).json({status:"ok", ...User});
}

Getting some problems in database saving

I'm getting problem in my database, I'm using mongoDB with mongoose npm package.
if (!authData) return res.redirect("/login")
const user = await process.oauth.getUser(authData.access_token);
// console.log(user)
let data = await Schema.findOne({
userID: user.id
})
if (!data) {
let e = await Schema.create({
userID: user.id,
})
await e.save()
let dataID = e._id.toString();
e.access_token = authData.access_token;
e.refresh_token = authData.refresh_token;
e.expires_in = authData.expires_in;
let secretAccessKeyy = jwt.sign({
userID: user.id,
uuid: dataID
}, jwtSecret)
/*
e.secretAccessKey = secretAccessKeyy
console.log(secretAccessKeyy)
*/
e.user = {
id: user.id,
username: user.username,
discriminator: user.discriminator,
avatar: user.avatar
};
await e.save()
await Schema.findOneAndUpdate({
userID: user.id
}, {
secretAccessKey: secretAccessKeyy
})
} else {
const id = data._id.toString();
data.access_token = authData.access_token;
data.refresh_token = authData.refresh_token;
data.expires_in = authData.expires_in;
let secretAccessKey = jwt.sign({
userID: user.id,
uuid: id
}, jwtSecret)
data.secretAccessKey = secretAccessKey
console.log(secretAccessKey)
data.user = {
id: user.id,
username: user.username,
discriminator: user.discriminator,
avatar: user.avatar
};
await data.save()
}
I have this code (its only data part not full code), it should check If there is data then overwrite data with new values other wise create a document, save It then again overwrite that document with new Objects then save.
Problems I'm Getting:
When I'm logging data its returning null but the data actually exists in database
the secretAccessKey is not saving in database
Would appreciate some help.
Thanks!

How to make a field of a document a primary key in firebase

So I want to prevent a document with same email field to get added into the firestore database.This is automatic in authentication but not in firestore.
This is my base function:
const register = async () => {
await addDoc(userCollectionRef, {username: userName, email: newUser, password: registerPassword})
try {
const user = await createUserWithEmailAndPassword(auth, newUser, registerPassword);
console.log(user);
}
catch(e) {
console.log(e.message);
console.log(e.code);
if((e.code) === "auth/email-already-in-use"){
window.alert("Email already registered");
}
}
}
What should i do to make email field a primary key?
Firestore doesn't have the concept of a primary key. The closest equivalent is the document ID.
If you want to specify your own document ID, use setDoc with a document reference instead of addDoc:
const userDocRef = doc(userCollectionRef, newUser)
await setDoc(docRef, {username: userName, email: newUser, password: registerPassword})
Also see the Firebase documentation on writing a document.
You should write in firebase after creating a user with email and password.
const register = async () => {
try {
const user = await createUserWithEmailAndPassword(auth, newUser, registerPassword).then(() => await addDoc(userCollectionRef, {username: userName, email: newUser, password: registerPassword})) ;
console.log(user);
}
catch(e) {
console.log(e.message);
console.log(e.code);
if((e.code) === "auth/email-already-in-use"){
window.alert("Email already registered");
}
}
}
As Frank mentioned above, there is no way, to achieve your purpose, you can make use of the Firebase createUser function in the sdk. If the user is already created, it will throw an error, and your write document to firebase will not be triggered.

How can I Update Document in Collection firebase

So I have this Avatar and I want to display the Avatar not only on the Profile but also on the Feed and some other pages. In my "User" collection, I have an object called "photoURL". What I’m trying to do is that when someone is adding or changing the Profile picture, the "photoURL" should update automatically in the collection.
My logic behind this is that I need this to display the photo on other pages and to do that I have to save it to the collection so I can access it.
Maybe my logic is wrong, I don't know, but I didn't find another way and I think this is the easiest.
This is the user collection code:
function onSignUp() {
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((result) => {
firebase
.firestore()
.collection("users")
.doc(firebase.auth().currentUser.uid)
.set({
name,
email,
role: isTeacher ? "pädagoge" : "parent",
photoURL: null,
});
console.log(result);
})
.catch((error) => {
console.log(error);
});
The Avatar Chooser Code :
async function handleFileInputChange(e) {
const files = e.target.files;
const file = files[0];
const storage = firebase.storage();
const usersImageRef = storage
.ref()
.child(`users/${user.uid}/profilepicture.jpg`);
const snap = await usersImageRef.put(file);
const donwloadURL = await snap.ref.getDownloadURL();
setDownloadURL(donwloadURL);
// Save photoUrl in user collection
// -> {name : "...", email : "...", role : "...", photoUrl : "..."}
await firebase.auth().currentUser.updateProfile({ photoURL: donwloadURL });
setProfilePictureUrl(donwloadURL);
}
I saw this example on firbase doc:
db.collection("users").doc("frank").update({
favorites: {
food: "Ice Cream"
}
}).then(function() {
console.log("Frank food updated");
});
But I would need the code to do it dynamically, and I'm not sure how.
you can add a .then() to your handleFileInputChange() function like this:
await firebase.auth().currentUser.updateProfile({ photoURL: downloadURL }).then(()=>{
db.collection("users").doc("frank").update({
userProfileImage: downloadURL
}).catch((err)=>{
//handle errors
});
}).catch((err)=>{
//handle errors
});
do take note of spelling of downloadURL too.
firebase
.firestore()
.collection("users")
.doc(firebase.auth().currentUser.uid)
.update({
name:name,
email:email,
role: isTeacher ? "pädagoge" : "parent",
photoURL: photourl,
});

Can I structure document collection of users that sign in using google auth provider?

So I am trying to do an app using React and Firebase and by now everything was fine.
In my app there are a few options to auth a user. Google, Email and Password and also Twitter.
When a user is creating an account using his email I can easily structure how the data will look like in my firestore for that user and I do it that way:
firebase.createUser(
{ email, password },
{
firstName,
lastName,
emailAddress: email,
birthDate: null,
activeStatus: false,
dateJoined: new Date(),
avatarUrl: null,
friends: [],
posts: [
{
content: "I have just joined!",
date: new Date(),
likes: [],
comments: [],
shares: []
}
]
}
).then(() => {
history.push("/login")
})
And the output in my firestore is something like that:
Firestore screen - email
Now I want to structure my data of users that Signed In using Google auth the same way.
This is how my Sign In using Google looks like:
const loginWithGoogle = () => {
firebase.login({ provider: 'google', type: 'popup' })
.then(() => {
localStorage.setItem('authUser', auth)
history.push("/home")
})
.catch(error => {
console.log(error.message)
})
}
And the output in the firestore by the default looks that way: Firestore screen - google
So my question is:
How do I even try to make both auth types collections look the same way? Should I somehow find out that the user is signing in for the first time using google provider and then try to structure that collection or is there a better approach to do that?
Thanks for all responses.
*******************************
For people who are struggling with that:
I did it thanks to #Ajordat response and this is how it looks and works perfectly fine for me:
const loginWithGoogle = () => {
firebase.login({ provider: 'google', type: 'popup' })
.then((user) => {
const fullName = user.profile.displayName.split(" ")
const firstName = fullName[0]
const lastName = fullName[1]
if (user.additionalUserInfo.isNewUser) {
firestore.collection("users").doc(user.user.uid).set({
...user.profile,
firstName,
lastName,
birthDate: null,
activeStatus: false,
dateJoined: new Date(),
friends: [],
posts: [
{
author: firstName + " " + lastName,
content: "I have just joined!",
date: new Date(),
likes: [],
comments: [],
shares: []
}
]
})
} else {
console.log("user exists")
}
localStorage.setItem('authUser', auth)
history.push("/home")
})
.catch(error => {
console.log(error.message)
})
}
You should use the method AdditionalUserInfo.isNewUser() in order to check if it's the first time a user is logging in. It will always be false except that one time, which you need to use to create the user on Firestore as you want it to be.

Resources