I have these two nodes that I need to get on a single http call. I am trying to achieve this by using async/await to get the two nodes and then combine them using concat or forEach. But it seems that even though I am awaiting responses, inside the function they are still promises and not the data itself. This is my basic example:
exports.searchVisit = functions.https.onRequest(async (req, res) => {
const today = new Date(Date.now());
let todayVisits = await admin.database().ref('/visits/').once('value');
let frequentVisits = await admin.database().ref('/frequent_visits/').once('value');
console.log(todayVisits); // Prints an object (I guess it is a promise)
res.status(200).send(todayVisits); // Returns correctly the data on visits collection
});
How could I achieve to return todayVisits and frequentVisits combined? Thanks in advance.
In your code, todayVisits is a DataSnapshot type object. It is not a promise. Logging that DataSnapshot object is not likely to be useful. If you want to see the raw data inside that snapshot, call val() on it to get a JavaScript object with the entire set of data in that snapshot. This is also what you probably want to send to the client (not the entire contents of the DataSnapshot).
The following code, merging the two JavaScript objects obtained with val(), as explained by Doug, should do the trick:
exports.searchVisit = functions.https.onRequest(async (req, res) => {
const today = new Date(Date.now());
let todayVisits = admin.database().ref('/visits/').once('value');
let frequentVisits = admin.database().ref('/frequent_visits/').once('value');
const [todayVisitsSnap, frequentVisitsSnap] = await Promise.all([
todayVisits,
frequentVisits
]);
res.status(200).send({ ...todayVisitsSnap.val(), ...frequentVisitsSnap.val() });
});
Related
I made a junction collection in containing references to other collections. Is it possible to get the data of the junction collection AS WELL AS the other collections data in one go?
This is an example of my Firestore schema!
For now I been looping through the field (eg. competitors) to get the data from firestore, but obviously we would like to lessen the count of call outwards. Please help thank you!
There's no way to query all those references at once. You'll have run those separate query separately. You can try the following:
const getData = async () => {
const groupRef = doc(db, "competitor_groups", "group_id");
const groupSnap = await getDoc(groupRef);
const eventsPromises = groupSnap.data().events.map((ev) => getDoc(ev))
const eventsData = eventsPromises.map((ev) => ev.data());
console.log(eventsData)
const eventsSnap = await Promise.all(eventsPromises);
}
I am working on react native application I use firebase as my backend. I fetch data from firebase real time database and render it on the page. But now I want my application to be supported offline.
I used following two functions for rendering.
For listings from database
const loadListings = () => {
let data = [];
listingRef.orderByChild("created_at").on("value", (snapshot) => {
data = [];
snapshot.forEach((listing) => {
data.push(listing.val());
});
cache.store("listings", data.slice(0, 10)); // only stores latest ten listings
setListings(data);
setLoading(false);
});
};
and then use it inside useEffect like.
useEffect(() => {
loadListings();
}, []);
and for listings from cache I used this.
const loadListingsCached = async () => {
let data = await cache.get("listings");
setListings(data);
};
Now I cant put a check inside firs function as effect hook will run only one time and initialy network status is null. its not defined.
how do I achieve this?
by the way link to package I used for detecting connectivity
Edit
I used this hook as second argument to useEffect() but didn't work for me
const netInfo = useNetInfo();
I
What you want to achieve is make the code different depending on what is the network status. In the answer linked by #Rohit there is my answer about how to check the network connectivity with Net Info Package.
What you have to do is make the effect dependant on the status change. You should pass it as a argument to the effect.
const netInfo = useNetInfo();
useEffect(() => {
loadListings();
}, [netInfo]);
This way the code will always run when a network change is detected. I hope this is what you wanted to achive. Please be more specific about you goal and what is the problem. Current questions does not specify if the hook is not working, or the rendering function does not trigger etc.
I am using a scheduled task in a Firebase Cloud Function to query an array which contains a number of objects that need to be updated if a matching condition exists. My current attempt is using the 'array-contains' method to get the objects, then loop over them to find a matching condition which will then batch update the items. This is my data structure:
I need to find an object that is <= the current time, and also if the 'active' value = false.
export const liveMeetingsTrigger = functions.runWith( { memory: '1GB' }).pubsub
.schedule('every 1 minutes').onRun(async context => {
const now = admin.firestore.Timestamp.now();
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'liveMeetingDate').get();
const batch = admin.firestore().batch();
liveMeetings.forEach(doc => {
if(doc.data().liveMeetingDate <= now && doc.data().active == false){
batch.update(doc.ref,'active',true);
}
});
return await batch.commit();
});
I have also tried using an exact object in the query instead of just using 'liveMeetingDate', but still get no results back, any help would be great - thanks.
Debugging: As the array I am trying to reach is inside of the (map) object 'liveMeetings' i have tried the dot notation (liveMeetings.meeting) with no success. Also trying a new collection with the the 'meeting' array at top level has provided no success.
Simple logging in the console (liveMeetings.size) shows that nothing is being returned on the query, so therefore the logging does not even reach the loop in the code.
As explained in this anwser the following query will not work:
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'liveMeetingDate').get();
because the meetings array contain some objects, instead of "simple" or primitive data (e.g. string, number...).
You could query it with the exact objects, like:
const obj = {active: false, liveMeetingDate: ..., meetingId: ..., ....};
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'obj').get();
Another approach would be to create a new collection which contains the similar documents (same Document ID) but with a meeting Array that contains only the liveMeetingDate property.
Finally, note that since your Array is within a map, you need to do
await admin.firestore().collection('fl_content').where('liveMeetings.meeting', 'array-contains', ...).get();
(PS: I don't mark this question as duplicate since you expressly ask for more help in the comments of the duplicate question/answer)
i am new in Vue JS and in Firebase. My target is get all 'eventos' that has same category. I mean, let's i have two eventos, an eventos category "SMIX" and another has "DAM". Now i want to get the eventos has category 'SMIX'
My data structure is here :
created() {
var datos = []
firebase.database().ref('usuarios').on("value", data => {
data.forEach(function(user){
user.child("eventos").orderByChild("categoria").equalTo("SMIX")
.forEach(function(evento){
datos.push(evento.val())
});
});
this.eventos = datos;
});
}[My data Structure][1]
There are several errors and points to be noted in your code:
Firstly, if you receive the error user.child(...).orderByChild is not a function
it is because with data.forEach(function(user) {...}), user is a DataSnapshot (see the forEach() doc), and by calling the child() method on this DataSnapshot you get another DataSnapshot... which does not have a orderByChild() method.
The orderByChild() method is a method of a Reference, so you need to do
user.child(...).ref.orderByChild()
using the ref property of the DataSnapshot
Secondly, you cannot do
user.ref.child("eventos").orderByChild("categoria").equalTo("SMIX")
.forEach()
because you need to use the once() or on() methods to get the data at a database location represented by a Reference.
Thirdly, Since you are going to execute several queries within a loop, you need to use the once() method instead of the on() method. The on() method set a listener that continuously "listens for data changes at a particular location."
Finally, note that you need to use Promise.all() to manage the parallel asynchronous queries to the database.
So, having noted all the points above, the following code will do the trick (to put in created()):
var datos = []
firebase.database().ref('usuarios').once('value')
.then(dataSnapshot => {
var promises = [];
dataSnapshot.forEach(user => {
promises.push(user.ref.child("eventos").orderByChild("categoria").equalTo("SMIX").once('value'));
});
return Promise.all(promises);
})
.then(results => {
//console.log(results);
results.forEach(dataSnapshot => {
dataSnapshot.forEach(evento => {
datos.push(evento.val());
});
});
this.eventos = datos;
});
First function observe any process. However, if first function will not send any response, i want to stop observer manually according to second function.When i call second function, observer does not stop in first function. How can i handle this situation ?
exports.startObserverFunc = functions.https.onRequest((req,res) => {
var userFirebaseID = req.query.firebaseID;
var ref = admin.database().ref("Quickplay");
let callback = ref.child(userFirebaseID).on("value",function(snapshot){
if (snapshot.exists()){
// Some Codes
ref.child(userFirebaseID).off("value", callback);
res.status(200).send({
resultName: "ok"
});
}
});
});
exports.stopObserverFunc = functions.https.onRequest((req,res) => {
var userFirebaseID = req.query.firebaseID;
var ref = admin.database().ref("Quickplay");
ref.child(userFirebaseID).off("value");
res.status(200).send({
resultName: "ok"
});
});
You should avoid using observers/listeners like this in Cloud Functions. It will likely not do what you want, given that your code could be running on any number of server instances, based on the load on your functions. Also, two function invocations are definitely not going to be running on the same server instances, so they have no knowledge of each other.
It's almost certainly the case that you just want to use once() to query for a single object just one time, and use that in your response. This is what all the official samples do.