Client is Offline error while using firebase realtime database - javascript

I am trying to make a small database system for my client that will capture his website's registered users name and there spent amount. Based on there spent amount he will get some gifts.
Using firebase realtime database i am able to store user spent amount but when i try to get data from database. I am getting the following Error from the line:
get(child(userDbRef, "User-ID-"+userID)):
"Uncaught (in promise) Error: Error: Client is offline."
initailData(); will work if user does not have data stored already and if the data has been stored once then runInitialFunction(); will work and get/retrieve data from database.
Here is my code
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.6.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
const firebaseConfig = {
apiKey: "AIzaSyAfA1HIkamXEFtDidPkpxaltDVsWpFWepE",
authDomain: "thundersmmpanel-77fb2.firebaseapp.com",
databaseURL: "https://thundersmmpanel-77fb2-default-rtdb.firebaseio.com",
projectId: "thundersmmpanel-77fb2",
storageBucket: "thundersmmpanel-77fb2.appspot.com",
messagingSenderId: "867306490186",
appId: "1:867306490186:web:93407cb6d8b0e9abe9d9b3"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
//<!--my code-->
import {getDatabase, ref, set, get, child, update}
from "https://www.gstatic.com/firebasejs/9.6.0/firebase-database.js";
const userID = {{user['id']}};
const userName = "{{user['username']}}";
const pointsDb = getDatabase();
//<!-- initial data -->
function initailData() {
set(ref(pointsDb, "User-ID-"+userID),{
UserName: userName,
InitialSpent: {{user['spent']}},
ThisRun: 1
})
.then(function(){
alert("Done");
})
.catch(function(error){
alert("Error "+error);
});
console.log("initailData");
}
function runInitialFunction() {
const userDbRef = ref(pointsDb)
get(child(userDbRef, "User-ID-"+userID)).then((snapshot)=>{
if(snapshot.exists()){
}else{
initailData();
}
});
console.log("runInitialFunction");
}
runInitialFunction();

Related

Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore

i have been solving this issue since past 2 days but cant get any idea of how it is solved
const handleSignUp = () => {
auth
.createUserWithEmailAndPassword(email, password)
.then(userCredentials => {
console.log(userCredentials.user.uid)
const user = userCredentials.user;
console.log('Registered with:', user.email);
setDoc(doc(db, "users", "LA"), {
name: "Los Angeles",
// state: "CA",
// country: "USA"
});
})
.catch(error => alert(error.message))
}
The Firebase module is here
if it need any changes of any dependency or any version
please suggest as firebase version is 9.6.11,while firestore is of 3.4.14
// Import the functions you need from the SDKs you need
// import firebase from "firebase";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
import firebase from "firebase/compat/app";
import "firebase/compat/auth";
import "firebase/compat/firestore";
import "firebase/compat/database"
// import { getFirestore } from "#firebase/firestore";
import { getFirestore } from 'firebase/firestore'
// import { getFirestore } from 'firebase/firestore/lite'
const firebaseConfig = {
apiKey: ........................
authDomain: ........................
projectId: ........................
storageBucket: ........................
messagingSenderId: ........................
appId: ........................
};
// Initialize Firebase
let app;
if (firebase.apps.length === 0) {
app = firebase.initializeApp(firebaseConfig);
} else {
app = firebase.app()
}
export const auth = firebase.auth()
// export const db = firebase.firestore();
export const db = getFirestore(app)
The error indicates that you are calling setDoc() function to something that is not a DocumentReference or a CollectionReference.
You may try to get the details from the console log as to which variable reference it is hitting the above error and understand why what you are calling it on is not a valid CollectionReference or DocumentReference. Please read through the helpful documentation for Collection Reference
The function setDoc() ,writes to the document referred to by the specified DocumentReference. If the document does not yet exist, it will be created. If you provide merge or mergeFields, the provided data can be merged into an existing document.The result of this write will only be reflected in document reads that occur after the returned promise resolves. If the client is offline, the write fails. If you would like to see local modifications or buffer writes until the client is online, use the full Firestore SDK.
Also check and verify that you are to call the firebase admin sdk rather than the client SDK and see if that works.
It's an AngularFire version issue, basically if you're using Angular 12, with Firebase 9 you need #angular/fire#^7.0
The compatibility table on the firebase page is key: https://github.com/angular/angularfire#angular-and-firebase-versions
I struggled with this issue for hours ?days? and it was because I had angularfire 7.4 (even 7.2 didn't work).

How to store data in the firebase realtime database

i need to store some simple data on the firebase realtime database, i've connected my app to the firebase realtime database, and imported all the requirments in the javascript file, but whenever my code is done, i check the realtime database and find that nothing is stored, i've followed many tutorials on youtube, even the firebase tutorial on youtube, but the mentionned problem stays, the realtime database stays empty as if i didn't write any code.
Here is the javascript code :
import { initializeApp } from 'firebase/app';
import { getDatabase, ref, set } from 'firebase/database';
const firebaseConfig = initializeApp({
apiKey: "AIzaSyChK5qg7AJi0_AZQAc2iWnvDVJjyJvz5iI",
authDomain: "mycoolapp-4373a.firebaseapp.com",
databaseURL: "https://mycoolapp-4373a-default-rtdb.firebaseio.com",
projectId: "mycoolapp-4373a",
storageBucket: "mycoolapp-4373a.appspot.com",
messagingSenderId: "895684408479",
appId: "1:895684408479:web:3341db270dcd768e085eaa"
});
const app = initializeApp(firebaseConfig);
function writeUserData(userId, username, email, message) {
const db = getDatabase();
const reference = ref(db, 'users/' + userId);
set(reference, {
username: username,
email: email,
message: message
});
}
writeUserData("andrew","andrew__8","andrew#gmail.com", "hey..i'm andrew!!");
is there any other working way ?

Firebase is not defined when connecting to Realtime Database Web

I am trying to connect my Realtime Firebase Database to my Web App and eventually store data in it.
I keep running into the same problem when loading my HTML file. The error I get in the console is Uncaught ReferenceError: firebase is not defined.
This is what my script looks like:
<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.5.0/firebase-app.js";
import { getAnalytics } from "https://www.gstatic.com/firebasejs/9.5.0/firebase-analytics.js";
const firebaseConfig = {
apiKey: "<api key>",
authDomain: "<domain>",
databaseURL: "<db url>",
projectId: "<project id>",
storageBucket: "<bucket>",
messagingSenderId: "<id>",
appId: "<app id>",
measurementId: "<id>"
};
const app = initializeApp(firebaseConfig);
const analytics = getAnalytics(app);
var database = firebase.database();
var postListRef = database.ref('posts');
var newPostRef = postListRef.push();
newPostRef.set({
"post1": "testing"
});
</script>
You're importing functions from Firebase using new v9 modular SDK syntax. In that syntax you have top-level functions like getDatabase(), instead of objects like firebase.database().
The equivalent of the Realtime Database code in your snippet is:
var database = getDatabase(app);
var postListRef = ref(database, 'posts');
var newPostRef = push(postListRef);
set(newPostRef, {
"post1": "testing"
});
I recommend keeping the Firebase documentation on reading and writing data, appending data to a list, and the modular upgrade guide handy.
If you have a lot of existing Realtime Database code, you can migrate in steps by importing the compat path first:
import firebase from 'firebase/compat/app';
import 'firebase/compat/database';

Even if the user is logged in, I get an error

I have a problem:
I want a logged in user to be able to use my getRealtimeUsers function. But I get the following error: FirebaseError: Missing or insufficient permissions.
Below you will find the code. Some explanations:
On the React side, I created a firebase, registered a getRealtimeUsers function there, and tried to use it.
firebase.js file
import firebase from "firebase/app";
import "firebase/firestore";
const firebaseConfig = {
apiKey: process.env.REACT_APP_FIREBASE_KEY,
authDomain: process.env.REACT_APP_FIREBASE_DOMAIN,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID
};
firebase.initializeApp(firebaseConfig);
export default firebase;
A function that uses the firebase I created:
import firebase from '../../firebase';
export const getRealtimeUsers = () => {
return async () => {
const db = firebase.firestore();
const unsubscribe = db.collection("users")
return unsubscribe;
}
}
Testing of the function
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getRealtimeUsers } from '../redux/actions/chatActions';
import firebase from '../firebase';
let unsubscribe;
class chat extends Component {
componentDidMount() {
unsubscribe = this.props.getRealtimeUsers()
.then(unsubscribe => {
return unsubscribe;
}).catch(error => {
console.log(error);
});
}
componentWillUnmount() {
return () => {
unsubscribe.then(f => f()).catch(error => console.log(error));
}
}
render() {
const ref = firebase.firestore().collection("users");
return (
<div>
check if works
</div>
);
}
}
const mapStateToProps = (state) => ({
});
export default connect(
mapStateToProps,
{
getRealtimeUsers
}
);
Here I let the user do the login
login.js action
export const loginUser = (userData) => (dispatch) => {
axios
.post('/login', userData)
.then((res) => {
console.log(res)
setAuthorizationHeader(res.data.token);
})
.catch((err) => {
console.log(err)
});
};
The login is done on the nodejs side, which is also where I set it to firebase:
const config = {
apiKey: "WqcVU",
authDomain: "c468.firebaseapp.com",
projectId: "c468",
storageBucket: "c468.appspot.com",
messagingSenderId: "087",
appId: "1:087:web:c912",
measurementId: "G-SQX1"
};
;
const firebase = require("firebase");
firebase.initializeApp(config);
// Log user in
exports.login = (req, res) => {
const user = {
email: req.body.email,
password: req.body.password,
};
firebase
.auth()
.signInWithEmailAndPassword(user.email, user.password)
.then((data) => {
console.log(JSON.stringify(data));
return data.user.getIdToken();
})
.catch((err) => {
console.error(err);
});
};
app.post('/login', login);
the rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
I want only a logged in user to use the getRealtimeUsers function, but even if the user is logged in it doesnt work. That's my problem.
I do not know at all how to solve it
Your case is really problematic, the only way to do security in rules is to access your correntUser or auth. Because you connect through the nodejs, you only return json object and there will be no access to these objects.
For you to have access to these objects what you need to do is connect once more, in react itself, with the same firebase and that's how you enjoy all the worlds that firebase has to offer.
When you log in again, the user does not need to know about it, since when you log in you will reset the password, and choose a random password, it will solve all your problems.
I think this is the most likely solution, but it is not for production
Please update me.
Is there a reason why you're not authenticating directly from the client? The thing is you have to pass in some way the authenticated state from the server to the front...
You have signed in with firebase on your server but you did not sign in with firebase on the front end. Or maybe you did in setAuthorizationHeader(res.data.token); but I'd be curious to know how you did that. It would have been interesting to be able to authenticate with nodejs and then send the tokenId which has been generated, that is data.user.getIdToken(), to the client which the client would then pass to firebase.auth().signInWithToken(token) but this is not possible. If you want to know more about it, I invite you to read this issue (a feature request).
The way to solve this problem is to use Admin SDK and create a custom token.
Firebase gives you complete control over authentication by allowing you to authenticate users or devices using secure JSON Web Tokens (JWTs). You generate these tokens on your server, pass them back to a client device, and then use them to authenticate via the signInWithCustomToken() method.
To achieve this, you must create a server endpoint that accepts sign-in credentials—such as a username and password—and, if the credentials are valid, returns a custom JWT. The custom JWT returned from your server can then be used by a client device to authenticate with Firebase (iOS, Android, web). Once authenticated, this identity will be used when accessing other Firebase services, such as the Firebase Realtime Database and Cloud Storage. Furthermore, the contents of the JWT will be available in the auth object in your Realtime Database Rules and the request.auth object in your Cloud Storage Security Rules.
Here are the steps:
First, you will add the SDK to your server:
yarn add firebase-admin --save
and import it
const admin = require("firebase-admin")
Go over to your Project settings under the "Service accounts" tab.
and click on "Generate a new private key"
a file has been downloaded and saved on your machine. From there, you will either import the file and initialize admin like this:
var serviceAccount = require("/path/to/serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
or better yet, in the console
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/serviceAccountKey.json"
and in your file
const credential = admin.credential.applicationDefault() // this will automatically find your env variable
admin.initializeApp({
credential
})
Note: don't forget to set the proper permissions to the private key file with chmod (I had to).
nodejs
firebase
.auth()
.signInWithEmailAndPassword(user.email, user.password)
.then((data) => {
admin
.auth()
.createCustomToken(data.user.uid)
.then((customToken) => {
console.log('customToken', customToken)
// send token back to client here
res.send(customToken)
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
})
.catch((err) => {
console.error(err);
});
and then on the client:
// get the token and then
firebase.auth().signInWithCustomToken(token)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
});
Another solution would be not using firebase on the client at all and use the backend as some sort of proxy between firebase and the client. The client would make a request to the backend which in turn would interrogate firebase.
in my case, faced same problem with rule's.
please give a try, change your rue and check whether its working or not

How to connect an expo app to google firestore?

I am trying to authenticate a user and also organize the users in my database by their uid and then have the data field be by email. The users are successfully being authenticated however nothing appears in my firestore database.
My firestore security rules are in test mode so there should be no issue with permissions. In my action dispatch, I am successfully getting the user from firebase with their uid, access token, and everything else. I believe the error must be some way I am trying to connect to the firestore.
In my app.js file I initialize firebase like this-
import firebase from 'firebase';
import '#firebase/firestore';
componentDidMount() {
const firebaseConfig = {
apiKey: 'xxxxxxxx',
authDomain: 'xxxxxxxxx.firebaseapp.com',
databaseURL: 'xxxxxxxx.firebaseio.com',
projectId: 'xxxxxxxx',
storageBucket: 'xxxxxxx.appspot.com',
messagingSenderId: 'xxxxxxxxxxx',
appId: 'xxxxxxxxxxxxxxxxxxxx'
};
firebase.initializeApp(firebaseConfig);
}
Then this is how I am trying to make the call to put the user into the database-
firebase.auth().createUserWithEmailAndPassword(email, password)
.then((user) =>
dispatch({ type: USER_LOGIN_SUCCESS, payload: user });
const dbRoot = firebase.firestore();
dbRoot.collection('users').doc(user.user.uid).set({ email });
});
Also at the top of that file, I am importing as follows
import firebase from 'firebase';
import '#firebase/firestore';
Again, these users are being successfully authenticated but they are not appearing in the firestore database.
You have to add a collection to the database and add data.
const dbRoot = firebase.firestore().collection('users');
...
addData() {
dbRoot.add({
user: user.user.uid,
email : email,
complete: true,
});
OR
const dbRoot = firebase.firestore().collection('users');
...
const defaultDoc = {
email: email
};
async addData() {
await dbRoot.doc(user.user.uid).set(defaultDoc);
}

Categories