Hope you're in good health.
I have a problem.
export function fetchListing() {
return function (dispatch) {
dispatch(fetchListingRequest());
//Getting Listing where status is in_review
firebase
.firestore()
.collection("listings")
.where("status", "==", "in_review")
.onSnapshot(
snapshot => {
const data = [];
snapshot.docs.forEach(doc => {
const temp = {};
// Getting address of business
firebase
.firestore()
.collection("users")
.doc(doc.data().business_id)
.get()
.then(users => {
temp["address"] = users.data().address;
})
.catch(error => {
dispatch(fetchListingFailed(error));
});
temp["title"] = doc.data().title;
temp["description"] = doc.data().description;
temp["listing_file"] = doc.data().listing_file;
data.push([doc.id, temp]);
});
dispatch(fetchListingSucess(data));
},
error => {
dispatch(fetchListingFailed(error));
}
);
};
}
I am Unable to get address in state but when I log it It displayed in console. I am able to access address when I am retrieving it from firebase and also in reducer I am also getting address.
reasons can be :
The hierarchy of your firestore collection
or you have to know that in js you can't affect the data to a variable that is in the main prog just when it is in a one level functions
for exemple here you can do this
locale = this ;
than you can use all the variables in two other levels
Related
I am creating a database for the products. The products are pushed into the database successfully but I am facing a problem in getting the data because the keys are nested. How can I target the nested key?
Please help me.
Using the below code I am getting my all the products data of currently logged in user.
useEffect(() => {
const getProductsData = async () => {
const userId = await AsyncStorage.getItem('uid')
database()
.ref(`Products/${userId}`)
.on('value', data => {
console.log(data.val())
});
}
getProductsData()
}, [])
console of the data.val()
Assuming that your userId is the dUD7M... value in the screenshot you shared, the data snapshot you get will contain the data for both child nodes in that screenshot. You can loop over those children with:
const userId = await AsyncStorage.getItem('uid')
database()
.ref(`Products/${userId}`)
.on('value', snapshot => {
snapshot.forEach((data) => { // 👈
console.log(data.val())
});
});
I have a problem, i have a Firebase Firestore Database connected to my React.JS Project, where users can enroll to courses. Now if i'm trying to load the users collection from the DB it returns 1 entry.
const fetchAthletes = async () => {
debugger
try {
const athletes: Array<any> = [];
const athleteRef = collection(db, COLLECTION_NAME_ATHLETE);
const getAthleteQuery = query(athleteRef, where('user', '==', userAuthToken.accessToken));
const querySnapshot = await getDocs(getAthleteQuery)
if (querySnapshot.docs) {
//this for each gets skipped, even when querySnapshot.doc has values in it
querySnapshot.forEach((doc) => {
athletes.push({
id: doc.id,
...doc.data()
});
setAthletes(athletes as Array<Athlete>);
})
}
} catch (error: unknown) {
enqueueSnackbar((error as string), { variant: 'error', autoHideDuration: 3000 })
}
}
But when i want to loop over it via array.prototype.map it always skips it.
I debbuged through the funtion and found out that docs from Firestore is set with values tbat i wanna recieve.
Data returned by Firestore
I have no clue why it doesn't work. Any idea or help is appreciated
Rather than attempt to individually set each doc into state, build up your array and set the entire thing into state
const querySnapshot = await getDocs(getAthleteQuery);
setAthletes(querySnapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
I have a script in Reactjs that get data (numbers) from api and addup this numbers with numbers from Firebase collection when user opens the page and the user can see this numbers.
There are going to be many users in the app and every user is going to have diffrent numbers from the same script
I was wondering if its possible with Firebase Cloud Functions to run this Client side script on the server and do the callculations of this numbers on the server and store this numbers in a Firestore collection.
im a begginer in nodejs and cloud functions i dont know if this is possible to do
get the numbers from Api
getLatestNum = (sym) => {
return API.getMarketBatch(sym).then((data) => {
return data;
});
};
Cloud function i was trying
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.resetAppointmentTimes = functions.pubsub
.schedule('30 20 * * *')
.onRun((context) => {
const appointmentTimesCollectionRef = db.collection('data');
return appointmentTimesCollectionRef
.get()
.then((querySnapshot) => {
if (querySnapshot.empty) {
return null;
} else {
let batch = db.batch();
querySnapshot.forEach((doc) => {
console.log(doc);
});
return batch.commit();
}
})
.catch((error) => {
console.log(error);
return null;
});
});
It is indeed possible to call a REST API from a Cloud Function. You need to use a Node.js library which returns Promises, like axios.
It's not 100% clear, in your question, to which specific Firestore doc(s) you want to write, but I make the asumption it will be done within the batched write.
So, something along the following lines should do the trick:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const axios = require('axios');
admin.initializeApp();
const db = admin.firestore();
exports.resetAppointmentTimes = functions.pubsub
.schedule('30 20 * * *')
.onRun((context) => {
let apiData;
return axios.get('https://yourapiuri...')
.then(response => {
apiData = response.data; //For example, it depends on what the API returns
const appointmentTimesCollectionRef = db.collection('data');
return appointmentTimesCollectionRef.get();
})
.then((querySnapshot) => {
if (querySnapshot.empty) {
return null;
} else {
let batch = db.batch();
querySnapshot.forEach((doc) => {
batch.update(doc.ref, { fieldApiData: apiData});
});
return batch.commit();
}
})
.catch((error) => {
console.log(error);
return null;
});
});
Two things to note:
If you want to add the API result to some fields value, you need to give more details on your exact need
Important: You need to be on the "Blaze" pricing plan. As a matter of fact, the free "Spark" plan "allows outbound network requests only to Google-owned services". See https://firebase.google.com/pricing/ (hover your mouse on the question mark situated after the "Cloud Functions" title)
I'm making a react-redux app with firetore as database.
Now, I wanted to use firebase cloud functions for handling stripe payments.
Here is the setup:
Below is the action method for checkout, after receiving token and amount from react side.
export const checkoutFunc = (token, amount) => {
return (dispatch, getState, { getFirebase, getFirestore }) => {
const uid = getState().firebase.auth.uid;
const ref = database.ref();
ref.child(`payments/${uid}`).push({
token: token,
amount: amount
});
};
};
This function creates a payment and saves token and amount.
Now, here is the cloud function which should "charge" the payment, after the above payment is created.
exports.stripeCharge = functions.database
.ref("/payments/{userId}/{paymentId}")
.onWrite((change, context) => {
const payment = change.after.val();
const userId = context.params.userId;
const paymentId = context.params.paymentId;
if (!payment || payment.charge) return;
return admin
.database()
.ref(`/teachers/${userId}`)
.once("value")
.then(snap => {
return snap.val();
})
.then(customer => {
const amount = payment.amount;
const idempotency_key = paymentId;
const source = payment.token.id;
const currency = "usd";
const charge = { amount, currency, source };
return stripe.charges.create(charge, { idempotency_key });
})
.then(charge => {
admin
.database()
.ref(`/payments/${userId}/${paymentId}/charge`)
.set(charge)
.then(charge => {
return true;
});
});
});
The creation of payment works and the token and amount is saved in payments table. But, the cloud function is not doing its job of charging the token.
Expected Result:
https://i.ibb.co/Fq9Zfhq/image.png
Actual result:
https://i.ibb.co/Krk7cGL/image.png
Though the answer provided by #Doug Stevenson is helpful, it was not the main problem. So, I am writing the solution here for other people struggling with it.
I was using the wrong public key and secret key pair in my app, that when I used correctly, it worked.
You're not returning the promise returned from set() using the Admin SDK. The function is terminating and cleaning up before that async work is complete.
.then(charge => {
return admin // add a return here
.database()
.ref(`/payments/${userId}/${paymentId}/charge`)
.set(charge)
.then(charge => {
return true;
});
});
FYI these promise chains are easier to visualize if you use async/await syntax instead of then/catch.
I try to put a listener on Firebase that will replicate a value in the matching element in Firestore.
exports.synchronizeDelegates = functions.database.ref(`delegates/{userId}/activities`).onUpdate((event) => {
const userKey = event.data.ref.parent.key
console.log("User Key:" + userKey)
return admin.database().ref(`delegates/${userKey}/email`).once('value', snapshot => {
let email = snapshot.val()
console.log("Exported Email:" + email)
const userRef = admin.firestore().collection('users')
const firestoreRef = userRef.where('email', "==", email)
firestoreRef.onSnapshot().update({ activities: event.data.toJSON() })
}).then(email => {
console.log("Firebase Data successfully updated")
}).catch(err => console.log(err))
}
)
This function is able to retrieve and locate the elemnt needed to target the right document in firestore, but the .update()function still error firestoreRef.update is not a function
I try several ways to query but I still have this error.
How to properly query then update a document in this scenario?
The onSnapshot() method of Query introduces a persistent listener that gets triggered every time there's a new QuerySnapshot available. It keeps doing this until the listener is unsubscribed. This behavior is definitely not what you want. Also, there's no update() method on QuerySnapshot that your code is trying to call.
Instead, it looks like you want to use get() to fetch a list of documents that match your query, then update them all:
exports.synchronizeDelegates = functions.database.ref(`delegates/{userId}/activities`).onUpdate((event) => {
const userId = event.params.userId
console.log("User Key:" + userKey)
return admin.database().ref(`delegates/${userId}/email`).once('value', snapshot => {
let email = snapshot.val()
console.log("Exported Email:" + email)
const usersRef = admin.firestore().collection('users')
const query = usersRef.where('email', "==", email)
const promises = []
query.get().then(snapshots => {
snapshots.forEach(snapshot => {
promises.push(snapshot.ref.update(event.data.val()))
})
return Promise.all(promises)
})
}).then(email => {
console.log("Firebase Data successfully updated")
}).catch(err => console.log(err))
}
Note that I rewrote some other things in your function that were not optimal.
In general, it's a good idea to stay familiar with the Cloud Firestore API docs to know what you can do.