This is my database structure below tutorCopy is the currentId of the user on basis of which I have to retrieve the user email but the problem is I can't get it, I have tried two methods but both are not working:
1st method with promise
componentWillMount(){
let user = firebase.auth().currentUser.uid;
const emailFetch = ["useremail"]
const emailpromise = emailFetch.map(id => {
return firebase.database().ref("tutorCopy/").child(user).child(id).on('value', s => s)
})
Promise.all(emailpromise)
.then(user => {
this.setState({ markers: s.values(s.val()) })
})
.catch(err => {
console.log(err)
})
}
Other one with snapshot:
componentWillMount(){
var user = firebase.auth().currentUser.uid;
var currId = JSON.stringify(user);
firebase.database().ref("tutorCopy/").child('user').once("value", snapshot => {
this.setState({ markers: Object.values(snapshot.val()) })
})
}
Related
I am trying to implement the nested query with Firestore in Cloud Functions but stumbled upon issues with reading values in a for loop. Are there ways to adjust the following code so I could do some operations after reading all records from a collection?
const firestore = admin.firestore();
const today = new Date();
const snap = await firestore
.collection('places')
.where('endDate', '<', today)
.get()
const userIds = [...new Set(snap.docs.map((doc: any) => doc.data().owner))];
const updatePromises = snap.docs.map((d: any) => {
return d.ref.update({
isPaid: false,
isActive: false
})
})
await Promise.all(updatePromises);
const userCol = firestore.collection('users');
const userDocs = await Promise.all(userIds.map(uid => userCol.doc(uid).get()));
const userData = userDocs.reduce((acc, doc) => ({
...acc,
[doc.id]: doc.data()
}), {})
snap.docs.forEach((l: any) => {
const ownerData = userData[l.owner];
const { email, displayName } = ownerData;
console.log(email, displayName);
const message = {
// Some values
}
return sendGrid.send(message);
})
return null;
{ owner: '<firebaseUid'>, address: 'Royal Cr. Road 234' }
{ email: 'asdfa#afsdf.com' }
<firebase_uid>: {
displayName: '',
email: '',
phoneNumber: ''
}
The userIds.push(owner); will keep adding duplicate values in that array and if a single user is owner of multiple locations, you'll end up querying same data multiple times. If you are trying to read owner's data along with a location, then try refactoring the code as shown below:
const firestore = admin.firestore();
const today = new Date();
const snap = await firestore
.collection('locations')
.where('isActive', '==', true)
.get()
const userIds = [...new Set(snap.docs.map(doc => doc.data().owner))];
const updatePromises = snap.docs.map((d) => {
return d.ref.update({
isPaid: false,
isActive: false
})
})
// update documents
await Promise.all(updatePromises);
const userCol = firestore.collection("users")
const userDocs = await Promise.all(userIds.map(uid => userCol.doc(uid).get()))
const userData = userDocs.reduce((acc, doc) => ({
...acc,
[doc.id]: doc.data()
}), {})
// To get data of a location's owner
// console.log(userData[ownerId])
snap.docs.forEach((l) => {
const ownerData = userData[l.owner]
// run more logic for each user
})
return null;
I'm trying to keep session stayed logged in after refreshing the browser. The user data that is being fetched is not rendering after being fetched. The console is saying "Cannot read properties of undefined (reading 'user'). This is my code for the login/sign up page.
The data I'm trying to access is in the picture below:
(Auth.js)
const Auth = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const [isSignup, setIsSignup] = useState(false);
const [inputs, setInputs] = useState({
name: "",
username: "",
email: "",
password: ""
})
const handleChange = (e) => {
setInputs(prevState => {
return {
...prevState,
[e.target.name]: e.target.value
}
})
}
const sendRequest = async (type = '') => {
const res = await axios.post(`/user/${type}`, {
name: inputs.name,
email: inputs.email,
username: inputs.username,
password: inputs.password,
}).catch(error => console.log(error))
const data = await res.data;
console.log(data)
return data;
}
const handleSubmit = (e) => {
e.preventDefault()
console.log(inputs)
if (isSignup) {
sendRequest("signup")
.then((data) => {
dispatch(authActions.login());
localStorage.setItem('userId', data.user._id);
navigate("/posts");
});
} else {
sendRequest("login")
.then((data) => {
dispatch(authActions.login());
localStorage.setItem('userId', data.user._id);
navigate("/posts");
});
}
}
Redux store file
const authSlice = createSlice({
name: "auth",
initialState: { isLoggedIn: false },
reducers: {
login(state) {
state.isLoggedIn = true
},
logout(state) {
state.isLoggedIn = false
}
}
})
export const authActions = authSlice.actions
export const store = configureStore({
reducer: authSlice.reducer
})
Chaining promises using .then() passes the resolved value from one to the next. With this code...
sendRequest("...")
.then(() => dispatch(authActions.login()))
.then(() => navigate("/posts"))
.then(data => localStorage.setItem('token', data.user))
You're passing the returned / resolved value from navigate("/posts") to the next .then() callback. The navigate() function returns void therefore data will be undefined.
Also, your redux action doesn't return the user so you can't chain from that either.
To access the user data, you need to return it from sendRequest()...
const sendRequest = async (type = "") => {
try {
const { data } = await axios.post(`/user/${type}`, { ...inputs });
console.log("sendRequest", type, data);
return data;
} catch (err) {
console.error("sendRequest", type, err.toJSON());
throw new Error(`sendRequest(${type}) failed`);
}
};
After that, all you really need is this...
sendRequest("...")
.then((data) => {
dispatch(authActions.login());
localStorage.setItem('userId', data.user._id);
navigate("/posts");
});
Since you're using redux, I would highly recommend moving the localStorage part out of your component and into your store as a side-effect.
I'm learning react and I'm having difficulty putting data from Firebase into the application state. I use Rebase but I am open to any solution!
still have an error similar to this one :
Thank you for your help !
Here is the code :
class App extends Component {
state = {
user:'',
vampires: {}
}
componentDidMount() {
if(this.state.user === ''){
firebase.auth().onAuthStateChanged(user => {
if(user){
this.handleUserLogin({ user })
this.setVampires({ user })
} else {
console.log('error')
}
})
}
}
setVampires = async (authData) => {
console.log(this.state.user)
await base.fetch(`/${authData.user.uid}/vampires`, { context: this })
.then(data => {
console.log(data)
let vampires = this.state.vampires;
vampires = {..._.cloneDeep(data)};
this.setState({vampires: {vampires}})
})
}
handleUserLogin = async authData => {
this.setState({user: authData.user.uid})
}
Your Firebase data is returned as an Object, with properties VampM5-..... React expects that you pass any repeated data as an array, not as an object.
So you'll need to convert the data from Firebase to an array, for example with:
await base.fetch(`/${authData.user.uid}/vampires`, { context: this })
.then(data => {
vampires = [];
data.forEach((child) => {
vampires.push({ ...child.val(), ".key": child.key });
})
this.setState({ vampires: vampires })
})
ive had a lot of trouble with firebase arrays, im now using push
I have this
I want to pull all the users down so I do this:
export const pullFromFirebase = () => {
return firebase
.database()
.ref("/users/")
.once("value")
.then(snapshot => {
var users = [];
snapshot.forEach(user => {
users.push(user.val());
});
return users;
});
};
this is fine
however, I now need the unique id -LI7d_i_BmrXktzMoe4p that firebase generated for me so that I can access this record (i.e. for updating and deleting) how do i do this?
You can get the key of the snapshot with the key property: https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#key
So you could change your code to this:
export const pullFromFirebase = () => {
return firebase
.database()
.ref("/users/")
.once("value")
.then(snapshot => {
var users = [];
snapshot.forEach(user => {
let userObj = user.val();
userObj.id= user.key;
users.push(userObj);
});
return users;
});
};
You can change this part:
snapshot.forEach(user => {
users.push(user.val());
});
To instead be:
let usersObj = snapshot.val()
for (var user_id in usersObj) {
users.push(Object.assign(usersObj[user_id], {
user_id: user_id,
});
});
That way, instead of each element in the users array only having email, name and username fields, it has user_id as well.
In my app, users are able to add a loved one, like so:
addLovedOne(event) {
const {
lovedOne,
} = this.state;
const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
if (user) {
db.addLovedOne(user.uid, lovedOne)
.then(() => {
this.setState({ lovedOne: '' });
this.refreshLovedOnes();
})
.catch(error => {
this.setState(byPropKey('error', error));
});
} else {
unsubscribe();
}
});
event.preventDefault();
}
Naturally, users are able to remove loved ones, like so:
removeLovedOne(event) {
const lovedOne = event.target.id;
const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
if (user) {
const ref = firebase.database().ref(`users/${user.uid}/lovedOnes`);
const removeLovedOne = ref.orderByChild('lovedOne').equalTo(lovedOne);
removeLovedOne.on('value', (snapshot) => {
const lovedOneId = snapshot.node_.children_.root_.key;
db.removeLovedOne(user.uid, lovedOneId, lovedOne)
.then(() => {
this.refreshLovedOnes();
})
.catch(error => {
this.setState(byPropKey('error', error));
});
});
} else {
unsubscribe();
}
});
}
Here is what the queries look like:
export const addLovedOne = (userId, lovedOne) => (
db.ref(`users/${userId}/lovedOnes`).push({
lovedOne,
})
);
export const removeLovedOne = (userId, lovedOneKey) => (
db.ref(`users/${userId}/lovedOnes/${lovedOneKey}/lovedOne`).remove()
);
Here is what my schema looks like:
Any idea why I'm not able to add a loved one with the same name after removing it without refreshing the page?