firebase is not defined, database.ref() is not a function - javascript

i have this issue of 'firebase is not defined' when i try to read and display data from the relatime database.
I am using firebase to host a simple site in which you input 4 values and receive a score back, everything is scored in the database. i then want to display the highest 10 scores from the database, and im having trouble doing that.
Ive seen lot of people having this issue, but their resolutions are not working for me
Here is my code
function displayTopScores() {
// Reference to the scores in the database
var scoresRef = firebase.database().ref("scores");
// Retrieve the top 10 scores
scoresRef.orderByChild("Score").limitToFirst(10).on("value", function(snapshot) {
var scores = snapshot.val();
// Array to store the top 10 scores
var topScores = [];
// Add the scores to the array
for (var score in scores) {
topScores.push(scores[score]);
}
// Sort the scores in descending order
topScores.sort(function(a, b) {
return b.Score - a.Score;
});
// Create a table to display the scores
var table = document.createElement("table");
table.setAttribute("class", "table table-striped");
// Add a header row to the table
var headerRow = table.insertRow(-1);
var nameHeaderCell = headerRow.insertCell(-1);
nameHeaderCell.innerHTML = "Name";
var scoreHeaderCell = headerRow.insertCell(-1);
scoreHeaderCell.innerHTML = "Score";
// Add a row for each score
for (var i = 0; i < topScores.length; i++) {
var row = table.insertRow(-1);
var nameCell = row.insertCell(-1);
nameCell.innerHTML = topScores[i].Name;
var scoreCell = row.insertCell(-1);
scoreCell.innerHTML = topScores[i].Score;
}
// Add the table to the HTML page
var scoresContainer = document.querySelector("#scores-container");
scoresContainer.innerHTML = "";
scoresContainer.appendChild(table);
});
}
const dbRef = ref(getDatabase());
get(child(dbRef, `scores/Scores`)).then((snapshot) => {
if (snapshot.exists()) {
console.log(snapshot.val());
} else {
console.log("No data available");
}
}).catch((error) => {
console.error(error);
});
i have imported (i think) all the right things for this to happen, but i am clearly doing some mistake i have not figured out.
here is what i import:
<script type="module">
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-app.js";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: "---",
authDomain: "---",
databaseURL: "---",
projectId: "---",
storageBucket: "---",
messagingSenderId: "---",
appId: "---",
measurementId: "---"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
import {getDatabase, set, get, update, remove, ref, child}
from "https://www.gstatic.com/firebasejs/9.15.0/firebase-database.js";
const database = getDatabase();
I've read the documentation on how to import the database and app function, looked at other people with the same issue, tried to ask openAI but with no luck.
tried using different ways of creating a reference and read the data.

You need to pass the app variable as a parameter to getDatabase() it should be getDatabase(app)
Here is the official code from the firebase documentation:
import { initializeApp } from "firebase/app";
import { getDatabase } from "firebase/database";
const firebaseConfig = {
// ...
databaseURL: "https://DATABASE_NAME.firebaseio.com",
};
const app = initializeApp(firebaseConfig);
const database = getDatabase(app);
You can follow further examples from the documentation here: https://firebase.google.com/docs/database/web/start#web-version-9

function displayTopScores() {
const dbRef = ref(getDatabase());
get(child(dbRef, `scores/`)).then((snapshot) => {
if (snapshot.exists()) {
console.log(snapshot.val());
document.getElementById("scores-list").innerHTML = console.log(snapshot.val());
} else {
console.log("No data available");
}
}).catch((error) => {
console.error(error);
});
}
its not complete solution cause i still cant show in my site the values from the database, but this seems to fix the issue at least in part, now i see the database getting read from the chrome dev tool

Related

Data not working in global scope but in local scope

I have been trying to make an e-commerce website and in that almost all things are done except for the database part. In which I have to fetch the data from firebase and use it in the products section.
I have fetched the data in local variables, however I want to store the data in a global scoped object, but it is not working.
So what I basically want is I want to fetch the data from firebase(DONE) and store it in global scope object(PENDING) so that I can use this object in other .js files.
Any kind of idea/advice/help/suggestion in more than welcomed!!
Thanks in advance!
This is my code:
https://jsfiddle.net/kumartanwar123/gseh4coq/
OR
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.6.7/firebase-app.js";
import { getAnalytics } from "https://www.gstatic.com/firebasejs/9.6.7/firebase-analytics.js";
// GLOBAL VARIABLES
var name, images, prices;
const firebaseConfig = {
apiKey: "--",
authDomain: "--",
databaseURL: "--",
projectId: "round-device-336118",
storageBucket: "round-device-336118.appspot.com",
messagingSenderId: "--",
appId: "--",
measurementId: "--",
};
const app = initializeApp(firebaseConfig);
firebase.initializeApp(firebaseConfig);
class firebase_class {
constructor(Images, Prices, Name) {
this.Images = Images;
this.Prices = Prices;
this.Name = Name;
}
}
// FIREBASE DATA FETCH
firebase
.database()
.ref("Practice")
.on("value", function (all_data) {
all_data.forEach(function (current_data) {
name = Object.keys(current_data.val().Name).map(
(keys) => current_data.val().Name[keys]
);
//In this if I use console.log(name) then it is working just fine, but not in outside the function.
images = Object.keys(current_data.val().Images).map(
(keys) => current_data.val().Images[keys]
);
prices = Object.keys(current_data.val().Prices).map(
(keys) => current_data.val().Prices[keys]
);
});
});
let firebase_object = new firebase_class(images, prices, name);
The problem is not where you access the database, but when you access it.
Data is loaded from Firebase (and pretty much all modern cloud APIs) asynchronously, and your main code (and thus the let firebase_object = new firebase_class(images, prices, name)) continues to execute while the data is loaded. Then when the data is available, your callback is invoked with it and it sets images, prices, and name.
And code that needs the data from Firebase has to be inside the callback, or be called from there. So:
// FIREBASE DATA FETCH
firebase
.database()
.ref("Practice")
.on("value", function (all_data) {
all_data.forEach(function (current_data) {
name = Object.keys(current_data.val().Name).map(
(keys) => current_data.val().Name[keys]
);
//In this if I use console.log(name) then it is working just fine, but not in outside the function.
images = Object.keys(current_data.val().Images).map(
(keys) => current_data.val().Images[keys]
);
prices = Object.keys(current_data.val().Prices).map(
(keys) => current_data.val().Prices[keys]
);
});
// 👇
let firebase_object = new firebase_class(images, prices, name);
... any use of firebase_object should be here too
});
Also check out:
Why Does Firebase Lose Reference outside the once() Function?

Firebase - Best way to safely check if and value exists

I'm having a list of E-Mail subscribers and want to add a new one on button click. This should be possible for non-logged-in users. Therefore there need to be a check if this entry is already in the database. As I don't want to expose the full list to the non-logged-in user, how would I check if an E-Mail address already exists without making a fetch GET request that is having rights to access that list with firebase, as the whole code is exposed in the frontend? I'm working with version Web9.
import { initializeApp } from "firebase/app";
import { getFirestore, collection, addDoc, getDocs, query, where } from "firebase/firestore";
import { getAuth } from "firebase/auth";
import { getAnalytics } from "firebase/analytics";
const firebaseConfig = {
apiKey: "",
authDomain: "",
projected: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: "",
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const db = getFirestore();
const auth = getAuth(app);
Fuction for adding the doc:
const addDocument = (dbName, obj) => {
return addDoc(collection(db, dbName), obj);
};
With the Firestore security rules you can break down a read rule into get and list as explained in the doc.
In your case you would assign read access to everybody with the get rule and deny access to the list rule. This way, the unauthenticated users can only fetch a specific document (identified with a specific email address) and verify if this given "entry" is already in the database. They cannot list all the existing entries.
Of course, a user could try many different email addresses but will not be able to directly get the list of all existing entries in the database with one query.
Here is my code solution that hopefully helps somebody. The goal has been to check if a single document exists and restrict the database access to check existence. I found only one possible option to do this (Excluding cloud functions). Thanks to #RenaudTarnec answer. There is no way to get a single doc with a query by field value. The only option is to set the id of the document to the specified E-Mail address (value you want to query).
Code:
Check if already subscribed, if not add to database of subscribers:
const [error, setError] = useState("");
const [message, setMessage] = useState("");
const handleSubmit = async (values: { email: string }) => {
const dbName = "newsletterSubscribers";
const docId = values.email;
setMessage("");
setError("");
const docRef = doc(db, dbName, docId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
// E-Mail address already subscribed, data: docSnap.data())
setMessage("E-Mail address already subscribed");
} else {
// E-Mail is not yet subscribed
try {
const docRef = await setDoc(doc(db, dbName, docId), {
createdAt: serverTimestamp(),
});
alert("Thank you for subscribing, you will receive all news and updates to " + values.email);
} catch (e) {
// Error adding document
setError("Failed to subscribe. We're sorry there was an error.");
}
}
};
Security rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /newsletterSubscribers/{subscriberId} {
allow get: if true;
allow list: if false;
allow create: if true;
}
}}

Cannot query from Firebase for my React Native app?

It seems I can retrieve all my data from my Firebase Realtime Database with the following:
let itemsRef = firebaseApp.database().ref('/');
itemsRef.on('value', (snapshot) => {
let data = snapshot.val();
let item = Object.values(data);
this.setState({item});
});
But when I try to query with specific parameters instead of just retrieving all the information, I always end up with this error:
#firebase/database: FIREBASE WARNING: Exception was thrown by user callback.
TypeError: Cannot convert undefined or null to object
This is how I'm trying to query information... literally following the documentation, and somehow my code works when I retrieve all information but not when the only change I make is adding a query?
let itemsRef = firebaseApp.database().ref('/');
itemsRef.orderByChild('roundedBPM').equalTo('100').on('value', (snapshot) => {
let data = snapshot.val();
let item = Object.values(data);
this.setState({item});
});
Is anyone else having problems querying from Firebase or am I doing something wrong?
This is how my data is structured on Firebase:
I would try initializing firebase in dbConfig.js for instance like so:
import * as firebase from 'firebase';
let config = {
apiKey: "XXXXXXX",
authDomain: "XXXXX",
databaseURL: "XXXXX",
projectId: "XXXXX",
storageBucket: "XXXX",
messagingSenderId: "XXXX"
};
firebase.initializeApp(config);
export default firebase;
I would import firebase where it's:
import firebase from './dbConfig.js'
let itemsRef = firebase.database().ref('/');
itemsRef.orderByChild('roundedBPM').equalTo('100').on('value', (snapshot) => {
let data = snapshot.val();
let item = Object.values(data);
this.setState({item});
});
Note: OrderByChild the element roundedBPM needs to be a direct child to the root path '/' if it's a nested child you could do something like this:
let itemsRef = firebase.database().ref('/users');
itemsRef.orderByChild('roundedBPM').equalTo('100').on('value', (snapshot) => {
...
});
Note: if you are setting equalTo() roundedBPM when it's a number and not a string you wouldn't get back any data. Make sure you use the correct type of data.
I hope this will help!

Is it possible to define a variable on the firebase database references path?

I am trying to redefine all my apps database references so that I can write a specific set of of firebase rules (I need to add buildings and depts nodes inside the user node – read why: What is the best practice to write the rules of Firebase in a situation like this? ).
I am using a firebase-config.js and exporting all my app's database references to the app's components so hopefully if I change this path I don't have to refactor the code on all the app's components.
I am trying to do it with a function (on my firebase-config.js file):
import * as firebase from "firebase";
import { mapState } from 'vuex';
import { store } from './store/store';
var config = {
apiKey: "XXXXXXXX",
authDomain: "XXXXXXXX.firebaseapp.com",
databaseURL: "https://XXXXXXXX.firebaseio.com",
projectId: "XXXXXXXX",
storageBucket: "XXXXXXXX.appspot.com",
messagingSenderId: "XXXXXXXX"
};
firebase.initializeApp(config)
export default !firebase.apps.length ? firebase.initializeApp(config) : firebase;
firebase.auth().onAuthStateChanged((user) => {
if (user) {
let userRef = firebase.database().ref('users').child(user.uid);
let buildingsRef = userRef.child('buildings');
}
})();
export const db = firebase.database();
export const usersRef = db.ref('users');
_// BUT THIS: "buildingsRef" is returning undefined!!! :(
export const buildingsRef = db.ref('users'+ "/" + buildingsRef) //buildingsRef is a variable
export const deptsRef = db.ref('depts');
The buldingsRef variable is returning undefined and it's writing the buildings to an undefined node.
{
"users" : {
"6hwNde08Wuaa9bfReR28niSbOsF3" : {
"name" : "João Alves Marrucho",
"userEmail" : "joaoalvesmarrucho#hotmail.com"
},
"undefined" : {
"-L9M4lM7oZFfmJKorxjC" : {
"address" : "",
"name" : "b1",
"ownerID" : "6hwNde08Wuaa9bfReR28niSbOsF3"
}
}
}
}
I writing to the node with the following method (vue.js):
addBuilding: function () {
let userId = firebase.auth().currentUser.uid;
let buildingKey = buildingsRef.push().key
this.newBuilding.ownerID = userId;
buildingsRef.child(buildingKey).set(this.newBuilding);
}
Any thoughts on why the variable buildingsRef is returning undefined?
Here is my full firebase-config.js file: http://jsfiddle.net/UnXrw/85/
If I understand your question, I think you want something like this:
firebase.auth().onAuthStateChanged(user => {
if (user) {
let userRef = firebase.database().ref('users').child(user.uid);
let buildingsRef = userRef.child('buildings');
// now do whatever you want with those refs
}
});

Get Firebase data to Algolia search indexing

I am trying to get a large dataset in Firebase database to Algolia for search indexing and every time I get a timeout error, what does that mean and how can I solve it?
I have created a node.js application to copy the data over and is as below. I can copy small data, say 10 contacts just fine, the problem is 3,000 contacts.
const algoliasearch = require('algoliasearch');
const dotenv = require('dotenv');
const firebase = require('firebase');
// load values from the .env file in this directory into process.env
dotenv.load();
// configure firebase
firebase.initializeApp({
databaseURL: process.env.FIREBASE_DATABASE_URL,
});
const database = firebase.database();
// configure algolia
const algolia = algoliasearch(
process.env.ALGOLIA_APP_ID,
process.env.ALGOLIA_API_KEY
);
const index = algolia.initIndex(process.env.ALGOLIA_INDEX_NAME);
// Get all contacts from Firebase
database.ref('/contactDetail/brazil').once('value', contacts => {
// Build an array of all records to push to Algolia
const records = [];
contacts.forEach(contact => {
// get the key and data from the snapshot
const childKey = contact.key;
const childData = contact.val();
// We set the Algolia objectID as the Firebase .key
childData.objectID = childKey;
// Add object for indexing
records.push(childData);
});
// Add or update new objects
index
.saveObjects(records)
.then(() => {
console.log('Contacts imported into Algolia');
})
.catch(error => {
console.error('Error when importing contact into Algolia', error);
process.exit(1);
});
});
I get a snippet of the contacts json and the following message:
contentLength: 854068,
method: 'POST',
timeouts: [Object],
url: '/1/indexes/app_NAME/batch',
startTime: 2018-01-17T20:35:27.239Z,
endTime: 2018-01-17T20:35:39.242Z,
duration: 12003 } ] }

Categories