I am using the on() method to retrieve a data snapshot in our database, but I need to be able to store this snapshot value so that I can use it to retrieve another separate snapshot.
Here is what our database looks like:
Firebase Real-Time Database
There is a node for users and a separate node for devices. Each user has a child "devices" which is a list of devices associated with that user. The user that I have expanded only has one device.
What I am trying to do is store this deviceID, and then do a separate query to find that device in the "Devices" node. Here is what my code looks like:
let uid = fireBaseUser.uid;
//get a reference to the database
let database = firebase.database();
let ref = database.ref("users/").child(uid).child("devices");
ref.on("value", getData);
And then the callback function looks like this:
function getData(data)
{
currentDevice = Object.keys(data.val())[0];
console.log("current device: " + currentDevice);
}
which is just grabbing the first device in the users device list and printing it to the console. I am trying to figure out how to
return this value so that I can use it when getting the data from the Devices tree. Which, I'm guessing,
would look something like this:
let deviceRef = database.ref("devices/").child(retrievedValue);
deviceRef.on("value", getData2);
Where retrievedValue is the deviceID that I got from the first query.
Is it possible to do this in javascript, or is there a better way? I know similar questions have already been asked, but I've found all the examples I've seen online to be really confusing and not very helpful for me. Any help at all would be super appreciated because I am kind of stuck on this. Thanks!
You have to learn about promises and asynchronous programming. Here are two ways to do what you want:
let uid = fireBaseUser.uid;
//get a reference to the database
let database = firebase.database();
let ref = database.ref("users/").child(uid).child("devices");
ref.once("value").then((data) {
currentDevice = Object.keys(data.val())[0];
console.log("current device: " + currentDevice);
let deviceRef = database.ref("devices/").child(currentDevice);
return deviceRef.once("value");
}).then((value) {
console.log("value is " + value);
})
or with async/await:
let uid = fireBaseUser.uid;
//get a reference to the database
let database = firebase.database();
let ref = database.ref("users/").child(uid).child("devices");
let data = await ref.once("value")
currentDevice = Object.keys(data.val())[0];
console.log("current device: " + currentDevice);
let deviceRef = database.ref("devices/").child(currentDevice);
let value = await deviceRef.once("value");
console.log("value is " + value);
I'm more confident about the second one as I'm typing these without testing.
These links would be helpful to start learning this stuff:
https://firebase.googleblog.com/2016/01/keeping-our-promises-and-callbacks_76.html
https://firebase.google.com/docs/functions/terminate-functions
Edit: I fixed the code above by replacing on with once. However now this is not listening to changes in the db anymore. To correct your code to listen to user's device changes:
let uid = fireBaseUser.uid;
//get a reference to the database
let database = firebase.database();
let ref = database.ref("users/").child(uid).child("devices");
ref.on("value", getData);
function getData(data) // may need to place this before the code above
{
currentDevice = Object.keys(data.val())[0];
console.log("current device: " + currentDevice);
let deviceRef = database.ref("devices/").child(currentDevice);
// no need to listen to this, as a change in one device would fire
// for every user. you probably don't want that.
deviceRef.once("value", (data) {
console.log(data);
});
}
In order to achieve that, you have to modify your callback as following:
function getData(data, callback)
{
currentDevice = Object.keys(data.val())[0];
console.log("current device: " + currentDevice);
callback(currentDevice)
}
Then we you call your callback from within the code, do it like this:
let uid = fireBaseUser.uid;
//get a reference to the database
let database = firebase.database();
let ref = database.ref("users/").child(uid).child("devices");
ref.on("value", getData((this_is_the_value_from_inside_callback) => {
console.log(`your value: ${this_is_the_value_from_inside_callback}`)
});
You can also try to run this little snippet (I used PlayCode), to see it more friendly testing environment
somefunction = (data, callback) => {
console.log(`data: ${data}`)
data += 100
console.log(`data: ${data}`)
callback(data)
}
somefunction(100, (dataReturned) => {
console.log(`data returned: ${dataReturned}`)
})
Related
I have a function that's doing calls for firebase database and return those data. I'm trying to implement a listener to this function so when the database updates, the content in my web site also updates without refresh.
My function is as follows
export const loadBookings = async () => {
const providersSnapshot = await firebase.database().ref('products').once('value');
const providers = providersSnapshot && providersSnapshot.val();
if (!providers) {
return undefined;
}
return providers;
};
After going through some documentation i have tried changing itto something like this
const providersSnapshot = await firebase.database().ref('products').once('value');
let providers = "";
providersSnapshot.on('value', function(snapshot) {
providers = snapshot.val();
});
But the code doesn't work like that. How can i listen in real time for my firebase call?
Use on('value') instead of once('value'). once() just queries a single time (as its name suggests). on() adds a listener that will get invoked repeatedly with changes as they occur.
I suggest reading over the documentation to find an example of using on(). It shows:
var starCountRef = firebase.database().ref('posts/' + postId + '/starCount');
starCountRef.on('value', function(snapshot) {
updateStarCount(postElement, snapshot.val());
});
I'm on a simple application:
It's my first try with firebase functions + realtime database.
The functions are going to be called by an external client application (e.g.: android).
if it was not javascript + nosqldb I would not have a problem, but here I am stuck, because I'm not sure for the best db structure and about transaction-like operations.
I. stored data:
user profile (id, fullname, email, phone, photo)
tickets amount per user
history for tickets buyings
history for tickets usings
II. actions:
user buy some tickets - should add tickets to the user's amount AND add a record to buyings history
user use some tickets - should remove tickets from the user's amount AND add a record to usings history
So my base problem is this ANDs - if it was a SQL db i would use a transaction but here I'm not sure what is db structure and js code in order to achieve same result.
EDITED:
======== index.js =======
exports.addTickets = functions.https.onCall((data, context) => {
// data comes from client app
const buyingRecord = data;
console.log(‘buyingRecord: ‘ + JSON.stringify(buyingRecord));
return tickets.updateTicketsAmmount(buyingRecord)
.then((result)=>{
tickets.addTicketsBuyingRecord(buyingRecord);
result.userid = buyingRecord.userid;
result.ticketsCount = buyingRecord.ticketsCount;
return result;
});
});
====== tickets.js =======
exports.updateTicketsAmmount = function(buyingRecord) {
var userRef = db.ref(‘users/’ + buyingRecord.userid);
var amountRef = db.ref(‘users/’ + buyingRecord.userid + ‘/ticketsAmount’);
return amountRef.transaction((current)=>{
return (current || 0) + buyingRecord.ticketsCount;
})
.then(()=>{
console.log(“amount updated for userid [“ + buyingRecord.userid + “]”);
return userRef.once(‘value’);
})
.then((snapshot)=>{
var data = snapshot.val();
console.log(“data for userid [“ + snapshot.key + “]:” + JSON.stringify(data));
return data;
});
}
exports.addTicketsBuyingRecord = function(buyingRecord) {
var historyRef = db.ref(‘ticketsBuyingHistory’);
var newRecordRef = historyRef.push();
return newRecordRef.set(buyingRecord)
.then(()=>{
console.log(‘history record added.’);
return newRecordRef.once(‘value’);
})
.then((snapshot)=>{
var data = snapshot.val();
console.log(‘data:’ + JSON.stringify(data));
return data;
});
}
You would have to use the callback, the request on Android to add or read data have an onSuccess or OnFailure CallBack, i used this to trigger my new request.
You can check this on the doc here :)
Also if instead of using RealTime Database you use Firestore you can use the FireStore Transactions here is the info.
I am faced with the problem of retrieving two data values of a single node from my firebase database and reference it in my javascript file but don't know how to go about it. I have been able to retrieve just one data value from a node (in this case "message") but I would like to add "from" as well. Most tutorials just reference one so I am really confused. So how do I get multiple data values?
This is my code...
JS file
exports.sendNotification7 = functions.database.ref('/GroupChat/{Modules}/SDevtChat/{SDevtChatId}/message')
.onWrite(( change,context) =>{
// Grab the current value of what was written to the Realtime Database.
var eventSnapshot = change.after.val();
var str = "New message from System Development Group Chat: " + eventSnapshot;
console.log(eventSnapshot);
var topic = "Management.Information.System";
var payload = {
data: {
name: str,
click_action: "Student_SystemsDevt"
}
};
// Send a message to devices subscribed to the provided topic.
return admin.messaging().sendToTopic(topic, payload)
.then(function (response) {
// See the MessagingTopicResponse reference documentation for the
// contents of response.
console.log("Successfully sent message:", response);
return;
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});
You can read from however many nodes you want in a Cloud Function. However, only one can trigger the function to run.
To read from your database use the following code:
admin.database().ref('/your/path/here').once('value').then(function(snapshot) {
var value = snapshot.val();
});
You will probably want to read from the same place that the Cloud Function was triggered. Use context.params.PARAMETER to get this information. For the example you posted your code would turn out looking something like this:
admin.database().ref('/GroupChat/'+context.params.Modules+'/SDevtChat/'+context.params.SDevtChatId+'/from').once('value').then(function(snapshot) {
var value = snapshot.val();
});
Just trigger your function one level higher in the JSON:
exports.sendNotification7 =
functions.database.ref('/GroupChat/{Modules}/SDevtChat/{SDevtChatId}')
.onWrite(( change,context) =>{
// Grab the current value of what was written to the Realtime Database.
var eventSnapshot = change.after.val();
console.log(eventSnapshot);
var str = "New message from System Development Group Chat: " + eventSnapshot.message;
var from = eventSnapshot.from;
...
I want to send some generated data to the to a specific object child.
var user = firebase.auth().currentUser;
var key = user.uid;
// Set path for created user to be UID
var createProfileRef = firebase.database().ref("profiles/" + key);
var info;
createProfileRef.on("value", function(snapshot) {
var getData = snapshot.val();
info = Object.keys(getData)[0];
});
// Save Plan to logged inn user
var sendData = firebase.database().ref("profiles/" + key + "/" + info + sendDate);
savePlan(sendFat, sendProtein, sendCarbohydrate);
function savePlan(sendFat, sendProtein, sendCarbohydrate) {
var addData = sendData.push();
addData.set({
Macros_Fat: sendFat,
Macros_Protein: sendProtein,
Macros_Carbohydrate: sendCarbohydrate,
});
The only thing I need for this to work is to get the value of the variable "info". I just can't get it to get transferred outside of the function it is declared in...
If I place the function savePlan inside the snapshot it works, but it generated around 1000 keys constantly until I exit the application.
The easiest way you can do that is by setting the variable value in localStorage in the firebase function itself and get it outside the function from localStorage.
Here's the code:
// in firebase function
localStorage.setItem('info',info)
//outside the firebase function
localStorage.getItem('info');
I am trying to create a function for my database using Cloud Functions for Firebase. The purpose of the function is to listen to write events on the attend table and based on the object written to identify the event and increment the usersAttending on the event object.
This is my function so far.
//listens to write on attendObjects (when a user is attending an event), and increments attending users for event
exports.listenAttendingEvents = functions.database.ref('/attend/{pushId}').onWrite(event => {
//get attendObj -> parsed JSON by javascript interpreter
const attentObj = event.data.val();
const attendId = attentObj['attendId'];
const pathToAttendees = '/attends' + '/' + attendId;
// Attach an asynchronous callback to read the data at our posts reference
admin.database().ref(pathToAttendees).on("value", function(snapshot) {
console.log(snapshot.val());
const obj = snapshot.val();
var nrAttending = obj['attending'];
nrAttending = Number(snapshot.val());
return admin.database().ref(pathToAttendees + '/attending').transaction(function (nrAttending) {
return (nrAttending || 0) + 1;
});
});
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
return errorObject
});
The problems as it seems is that the event object doesn't get retrieved. The function seems to finish before that with the status ok
The problem was that I was not having a promise for my top-level function. This caused Google Cloud Functions to kill it before the operation was complete.
Adding a promise solved my problem
admin.database().ref(pathToAttendees).once("value").then( function(snapshot) {