Retrieve data in Firebase exactly once - javascript

I have a real time database with firebase and i'm using the following code to connect to the database and get some data from it.
window.onload = function(){
var databaseWebsites = firebase.database().ref('/websites').orderByChild('votes');
console.log(databaseWebsites);
databaseWebsites.on('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var webTemp = document.getElementById(childSnapshot.val().id);
webTemp.style.order = order;
var webText = webTemp.getElementsByClassName('likeText');
webText[0].innerHTML = childSnapshot.val().votes;
order--;
});
order = 0;
});
It gets all the data, in order and uses it correctly.
The problem is, I don't want the data on the front end to update until the user refreshes the page. The system is a voting system that is ordered by votes value, if it was constantly updating it would be a bad user experience.
Any help will be appreciated.
Thanks

Change the on to once, Firebase on listens for changes in your database node and sends a response.
databaseWebsites.on('value', function(snapshot) {
to
databaseWebsites.once('value', function(snapshot) {
An excerpt from Firebase doc
The value event is called every time data is changed at the specified
database reference, including changes to children. To limit the size
of your snapshots, attach only at the lowest level needed for watching
changes.
Visit this url to read more

The accepted response is not correct (maybe outdated?) because once() requires to add a then()
It's actually
databaseWebsites.once('value').then(function(snapshot) {}
that replaces
databaseWebsites.on('value', function(snapshot) {}

Related

Prevent the delay time to fetch the data from firebase (Please check details for clarity)

Note:
The asynchronous nature of firebase has been discussed thousands of times here, but my low reputation number does not allow for a comment on an existing question. That's why I have asked this question.
I am a noob, so please help me understand the implementation in an easy to understand manner.
Steps to implement:
User enters a value in the HTML input box
Search the input value in the firebase db (showMessage() gets called)
Display an appropriate result based on the search result in step 2
Problem faced:
The message displayed in step 3 takes almost an average of 1.75 seconds to display. This experience is not user-friendly. I want to display the message as soon as possible i.e. want to reduce the fetch time.
Probable root causes:
Either my way of fetching the data from firebase dB is incorrect (I still don't understand how to keep a promise :()
Or The mechanism of search and display is not right
var full_name;
function showMessage(){
extractData();
}
function extractData(){
test(function(returnValue) {
custom_message = searchMessage(returnValue);
var container = document.querySelector('#placeholder');
var para = document.createElement('p');
var custom_message = "Happy happy, buds!";
para.innerHTML = custom_message;
para.className = "message";
container.appendChild(para);
});
}
function test(callback) {
var ref = firebase.database().ref();
ref.on('value', function(snapshot) {
var data = snapshot.val();
callback(data);
}, function (error) {
console.log("Error: " + error.code);
});
}
function searchMessage(data){
for(var i = 0; i < data.length; i++)
{
name_f_data = data[i].firstName.concat(" ", data[i].lastName);
if(full_name.toLowerCase() == name_f_data.toLowerCase())
{
console.log(name_f_data.toLowerCase());
console.log(full_name.toLowerCase());
return data[i].message;
}
}
}
The time a read operation takes depends on:
The latency of your connection to Firebase's servers
The amount of data you are reading
The bandwidth of your connection
The time it takes Firebase to process the request
In most cases, the time Firebase takes is only a very small portion of the total time, and most of your time actually goes to the data transfer, which depends purely on the bandwidth and amount of data. If this is the first time you're reading data from Firebase in the page, the latency also matters more, as Firebase has to establish a connection, which takes a few roundtrips.
Your current code is downloading all data from the database, and then searching in the JavaScript code for a child node that matches a certain value. The best way to reduce the time that takes (apart from upgrading to a fast connection) is to transfer less data, which you can do by using Firebase's query mechanism to do the filtering on the server.
You can get pretty close with:
var ref = firebase.database().ref();
var query = ref.orderByChild().startAt(firstName).endAt(firstName+"~");
query.once('value', function(snapshot) {
var data = snapshot.val();
callback(data);
This will significantly reduce the amount of data transferred. A few notes though:
The query returns just the people that have the first name you're looking for. It does not yet filter on the last name, so you'll still need to filter that in the client-side code.
To further optimize this, store the full name (which you now compose in the client-side code) in the database so that you can query on that and reduce data transfer even more.
Firebase queries are case sensitive, so the query only returns data where the case matches exactly. If you want to query case-indifferent, consider storing a toLowerCase() value in the database.
Be sure to define an index on firstName, as otherwise the Firebase database will still send all data to the client, and the SDK will perform the filtering client-side.

In firebase (javascript), how can I get data for the currently logged in user?

I've spent a few days researching for the solution. I have found many answers that were quite helpful, but still I haven't been able to find a solution that fully resolved my problem. Basically all I want to do is to get current user's data (stored in firebase realtime database) and display them on the user's screen.
So far, I can display data for all the user. But how can I have it display data for only the current user? (How can I get the push key of only the current user?)
I'm not an experienced programmer (less than a year). Please use a language that is easy to understand.
I've gone through all the firebase documentation. Please don't just give me the copy of the documentation or the link to it.
Screenshot: Firebase realtime database
Screenshot: JavaScript function for retrieving current user's data
Additional JavaScript screenshot
User data is wherever you choose to store it--other than name, email, and a few other fields, the User object cannot actually store any other info. Therefore, you will need to decide where in the database you want to keep your extra data.
Assuming you choose to create a collection users with children named by uid, and you store the users' countries in those documents, the following will get you a specific user's data and you can use whatever fields you'd like from there:
let ref = database.ref('/users/' + currentUser.uid).once('value').then(function(snapshot) {
let userData = snapshot.val();
console.log(userData.country);
}
Here you go!
function showUser(){
var usref=firebase.database().ref("countries/"+uid);
//uid here is the unique code u gave to the specif user
usref.once('value', function(snapshot) {snapshot.forEach(function(childSnapshot) {
if((childSnapshot.key)=="country"){
var country = childSnapshot.val();
//use this variable here enter code here
window.alert(country);//just for checking!!!
}
if((childSnapshot.key)=="age"){
var name = childSnapshot.val();
//use this variable here
window.alert(name);//just for checking!!!
}
});
});
}
I hope this code works for you.

Firebase Javascript: Creating a numeric Index on File Upload to Firebase Realtime

I've got a little app that allows me to upload files, one at a time, to firebase storage. In the process it creates a database reference where it stores the user that uploaded it, the downlodurl etc.
However I have hit an issue as I want to serve back to the user their uploads at random, which is not something easily done by firebase DB at the moment (it would seem - happy to be proven wrong though!!) so I was wondering if it was possible on upload to create a numeric index field that auto increments after every upload?
Would it be as simple as querying the database pulling the max value for the current index and then +1 to it?
Below is the (fairly boilerplate) database referencing bit of the code where I would want to add the index number:
var imagekey = firebase.database().ref('images/').push().key;
var downloadURL = uploadTask.snapshot.downloadURL;
var updates = {};
var postData = {
url: downloadURL,
index:
user: user.uid
};
updates ['/images/'+imagekey] = postData;
firebase.database().ref().update(updates);
});
Ok thanks to the help of Frank below I was able to write the following function to create a data base reference of "index" and increase it by one on every single upload:
var indexRef = firebase.database().ref('index');
indexRef.transaction(function(currentRank) {
return currentRank + 1;
});
However it did have an incredibly odd effect when inserted into my upload function - the upload would continue to work, the file would appear in storage - but only the index database reference would be written, all other information would be lost and I would get an incredibly complex error in the console. Here is the updated code - any ideas as to what I may have done incorrectly?
function complete(){
//write a database reference
var indexRef = firebase.database().ref('index');
indexRef.transaction(function(currentRank) {
return currentRank + 1;
});
var imagekey = firebase.database().ref('images/').push().key;
var downloadURL = uploadTask.snapshot.downloadURL;
var updates = {};
var postData = {
url: downloadURL,
score: 1500,
index: indexRef,
user: user.uid
};
updates ['/images/'+imagekey] = postData;
firebase.database().ref().update(updates);
});
}
If you want to write a value to the database, based on a value that is currently in the database, you'll use transactions.
The trickiest bit with transactions is that they work on a single location in the database. With the data model you propose, you'd be reading from one post (highest index so far) to then write to another one. That would mean that you need a transaction on the entire images node, which is a huge problem for scalability.
What you'll likely want to do is keep a "highest used counter value" somewhere in a single spot and then "claim next value and write updated value" on that in a transaction. That means read-and-update the counter in a transaction, and then write the image with the index you just claimed.

Firebase JS SDK on 'child_added' not working on large database

I have ~ 1 million users in my users "table" on Firebase.
I need to fetch the username of each user.
once('value' is a way too big of a call, so I try using on 'child_added' but without any success, I am using this code:
usersRef.on('child_added', function (snapshot) {
var user = snapshot.val();
console.log(user);
var username = user.username ? user.username : null;
// Put username in the .txt file, one username per line
});
I waited as much as 15 minute, and nothing happened. It seems to be impossible right now. What could I try besides child_added?
Retrieving one million nodes is very unlikely to ever work. You're simply trying to pull too much data over the network. In that respect there is no difference between value and child_added: both retrieve the same data over the network in the same way.
Limit the number of children you retrieve by a query, either by a query:
var ref = firebase.database().ref("users");
ref.orderByChild("username").equalTo("Dan P.").on("child_added", ...
or by directly accessing the user's node:
var ref = firebase.database().ref("users");
var user = firebase.auth().currentUser;
ref.child(user.uid).on("child_added", ...

Is "ref.off()" the correct approach to disconnect from Firebase Database after reading data?

We have scenarios where we read data from the Firebase Database and then disconnect (we do not care to receive updates on that data). We use code like the snippet below:
ref.once('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var childKey = childSnapshot.key;
var childData = childSnapshot.val();
// Display the data
});
});
We use ref.once() because we care to read the data all at once, we understand that there's monitoring set on the data nonetheless by Firebase.
What's the best approach to stop the monitoring, and should we even attempt that in an effort to reduce resources consumed, etc.? We tried ref.off() and that didn't seem to make a difference.
As per the official document, you don't need to call off().
In some cases you may want a snapshot of your data without listening for changes, such as when initializing a UI element that you don't expect to change. You can use the once() method to simplify this scenario: it triggers once and then does not trigger again.
This is useful for data that only needs to be loaded once and isn't expected to change frequently or require active listening. For instance, the blogging app in the previous examples uses this method to load a user's profile when they begin authoring a new post:
var userId = firebase.auth().currentUser.uid;
return firebase.database().ref('/users/' + userId).once('value').then(function(snapshot) {
var username = snapshot.val().username;
// ...
});

Categories