how to send data to firebase database in function - javascript

I'm trying to send data to firebase. The data is saved to the database after the function is performed, how can I overwrite it during the function execution?
import firebase from 'firebase';
var config = {
apiKey: "xxx",
authDomain: "xxx.firebaseapp.com",
databaseURL: "https://xxx.firebaseio.com",
projectId: "xxx",
storageBucket: "xxx.appspot.com",
messagingSenderId: "xxx"
};
firebase.initializeApp(config);
var db = firebase.database();
var sleep = require('sleep');
function run(TIME) {
db.ref('/test/').child('status').set('1');
sleep.sleep(TIME);
db.ref('/test/').child('status').set('2');
sleep.sleep(TIME);
db.ref('/test/').child('status').set('3');
sleep.sleep(TIME);
db.ref('/test/').child('status').set('4');
};
//========================================<<<< Now I see status in Firebase
run(5);

The set() method is asynchronous and returns a promise that resolves when write to server is complete, as explained in the doc here.
From you comment above I understand you want to have a status "WORKING - before starting function and DONE after".
So you should do something along the following lines:
var status = '';
var adaNameRef = firebase.database().ref('users/ada/name');
status = 'WORKING';
adaNameRef.set({ first: 'Ada', last: 'Lovelace' })
.then(function() {
status = 'DONE';
})
.catch(function(error) {
console.log('Synchronization failed');
});
If you want to "write multiple values to the Database at once", you should use the update() method. See here and here.
Similarly to the set() method, the update() method is asynchronous and returns a promise that resolves when write to server is complete, so you would use the same logic to update the value of status
UPDATE following your comment
1. Send status 'WORKING' to FB 2. Set Relay to ON 3. Wait x seconds 4. Send status 'DONE' to FB 5. Set Relay to OFF
If I understood correctly, this should work (not tested however):
var adaNameRef = firebase.database().ref('users/ada/name');
adaNameRef.set({ status: 'WORKING'})
.then(function() {
// Set Relay to ON ... don't know exactly how you "set the relay"
sleep.sleep(x);
return adaNameRef.set({ status: 'DONE'})
})
.then(function() {
// Set Relay to OFF
})
.catch(function(error) {
console.log(error);
});

Related

I cannot get data from firebase database

I am new to firebase. I'm trying to retreive data from a real time database using a node.js server sending associated credentials to firebase, but something gets broken after once('value') is called: its returned promise never gets resolved and server stops itself logging this message: "Process exited with code 3221226505".
I wrote the following code:
async function testFirebase1(firebaseCredentialsObj, path) {
let firebase = require('firebase')
firebase.initializeApp(firebaseCredentialsObj);
var database = firebase.database();
var ref = database.ref(path);
console.log(ref.toString());
try {
// Attempt 1
var prom = await ref.once('value');
const data = prom.;
console.log('data ' + data)
// Attempt 2
prom.then((snapshot) => {
console.log('snapshot ' + snapshot)
}).catch((error) => { console.log(error)} )
} catch (error) {
console.log(error)
}
}
No error ever gets catched.
I also tried to get data as an admin, but i got the same failing result
async function testFirebase3(firebaseCredentials, serviceAccountKey, databaseURL, path) {
const admin=require('firebase-admin');
const serviceAccount = serviceAccountKey;
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: databaseURL
});
var db=admin.database();
var userRef=db.ref(path);
const prom = await userRef.once('value');
console.log(prom)
}
Promise returned from once() method keep beeing pendent. This is its log:
[[PromiseStatus]]:'pending'
[[PromiseValue]]:undefined
Server is supposed to get databases'data in json format and send it to the client.
Why is this happening?
Based on your code, you are mixing traditional Promise chaining and async/await syntax together which is leading to your confusion.
Note: In the below snippets, I use the database query coding style I describe at the end of this answer.
SDK Initialization
To start with, in both testFirebase1 and testFirebase3, you initialize the default Firebase app instance in the function. If you call either function only once, you won't experience any problems, but any time you call them another time, they will always throw an error stating that the app has already been initialized. To solve this, you can lazily load these libraries using the following functions:
function lazyFirebase(options, name = undefined) {
const firebase = require('firebase');
// alternatively use the Promise-based version in an async function:
// const firebase = await import('firebase');
try {
firebase.app(name);
} catch (err) {
firebase.initializeApp(options, name);
}
return firebase;
}
function lazyFirebaseAdmin(options, name = undefined) {
const admin = require('firebase-admin');
// alternatively use the Promise-based version in an async function:
// const admin = await import('firebase-admin');
try {
admin.app(name);
} catch (err) {
const cred = options.credential;
if (typeof cred === "string") {
options.credential = admin.credential.cert(cred)
}
admin.initializeApp(options, name);
}
return admin;
}
Important Note: Neither of the above functions checks whether they use the same options object to initialize them. It just assumes they are the same configuration object.
Correcting testFirebase1
In testFirebase1, you are initializing the default Firebase app instance and then starting the process of the getting the data from the database. Because you haven't returned the promise from the ref.once('value') in the function, the caller will get a Promise<undefined> that resolves before the database call completes.
async function testFirebase1(firebaseCredentialsObj, path) {
let firebase = require('firebase')
// bug: throws error if initializeApp called more than once
firebase.initializeApp(firebaseCredentialsObj);
// bug: using `var` - use `const` or `let`
var database = firebase.database();
var ref = database.ref(path);
console.log(ref.toString());
try {
// Attempt 1
// bug: using `await` here, makes this a DataSnapshot not a Promise<DataSnapshot>
// hence `prom` should be `snapshot`
// bug: using `var` - use `const` or `let`
var prom = await ref.once('value');
// bug: syntax error, assuming this was meant to be `prom.val()`
const data = prom.;
console.log('data ' + data)
// Attempt 2
// bug: a `DataSnapshot` doesn't have a `then` or `catch` method
// bug: if `prom` was a `Promise`, you should return it here
prom
.then((snapshot) => {
console.log('snapshot ' + snapshot)
})
.catch((error) => {
console.log(error)
})
} catch (error) {
console.log(error)
}
}
Correcting these problems (and making use of my coding style when dealing with RTDB queries) gives:
async function testFirebase1(firebaseCredentialsObj, path) {
const firebase = lazyFirebase(firebaseCredentialsObj);
const snapshot = await firebase.database()
.ref(path)
.once('value');
// returns data at this location
return snapshot.val();
}
Correcting testFirebase3
In testFirebase3, you are initializing the default Firebase Admin app instance and correctly waiting for the data from the database. Because you haven't returned the data from the database, the caller will get a Promise<undefined> that resolves when the database call completes but without the containing data.
async function testFirebase3(firebaseCredentials, serviceAccountKey, databaseURL, path) {
const admin = require('firebase-admin');
// note: unnecessary line, either call `serviceAccountKey` `serviceAccount` or use `serviceAccountKey` as-is
const serviceAccount = serviceAccountKey;
// bug: throws error if initializeApp called more than once
// bug: `firebaseCredentials` is unused
// note: when initializing the *default* app's configuration, you
// should specify all options to prevent bugs when using
// `admin.messaging()`, `admin.auth()`, `admin.storage()`, etc
// as they all share the default app instance
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: databaseURL
});
// bug: using `var` - use `const` or `let`
var db=admin.database();
var userRef=db.ref(path);
// bug: using `await` here, makes this a DataSnapshot not a Promise<DataSnapshot>
// hence `prom` should be `snapshot`
const prom = await userRef.once('value');
// bug: logging a `DataSnapshot` object isn't useful because it
// doesn't serialize properly (it doesn't define `toString()`,
// so it will be logged as "[object Object]")
console.log(prom)
}
Correcting these problems (and making use of my coding style when dealing with RTDB queries) gives:
async function testFirebase3(firebaseCredentials, serviceAccountKey, databaseURL, path) {
const admin = lazyFirebaseAdmin({
...firebaseCredentials, // note: assuming `firebaseCredentials` is the complete app configuration,
credential: serviceAccountKey,
databaseURL: databaseURL
});
const snapshot = await admin.database()
.ref(path)
.once('value');
return snapshot.val();
}

Vue and Firebase RTDB connection

I have followed few different tutorials, read numerous posts on SO, but still my firebase RTDB won't connect. It doesnt even throw any error.
At this point my file in db/database.js looks like this (I stripped it from connection data):
const firebaseConfig = {
apiKey: "key",
authDomain: "",
databaseURL: "https://database_name.europe-west1.firebasedatabase.app",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: ""
};
firebase.initializeApp(firebaseConfig);
const firebaseDb = firebase.database()
export default firebaseDb
the method that I use to call the database ref in store/index.js
dbReadSettings() {
console.log("I'm here");
let settings = firebaseDb.ref('userSettings/', function(error) { console.log(error) });
settings.on('value', (snapshot) => {
const data = snapshot.val();
console.log(data)
}, function(error) {
console.log(error) })
}
The result is none – the console logs out I'm here" and then nothing else (I tried many different ways). I checked the path and the documentation but it does not connect at all. Any help?
the ref method only receives one parameter.
dbReadSettings() {
console.log("I'm here");
let settings = firebaseDb.ref('userSettings/');
settings.on('value', (snapshot) => {
const data = snapshot.val();
console.log(data)
}, (error) => {
console.log(error)
})
}
That first callback you have is not needed, and will in fact never be called. Since you attach the listener inside that callback, the listener will never be attached.
You can easily check this by adding an extra log line:
console.log("I'm here");
let settings = firebaseDb.ref('userSettings/', function(error) { console.log(error) });
console.log("Now I'm here");
settings.on('value', (snapshot) => {
const data = snapshot.val();
console.log(data)
}, function(error) {
console.log(error);
});
})
While you'll see:
I'm here
You'll never see:
Now I'm here
To fix this, remove the extraneous callback and just attach the listener right after you create the reference (which is not an asynchronous operation):
console.log("I'm here");
let settings = firebaseDb.ref('userSettings/')console.log(error) });
settings.on('value', (snapshot) => {
const data = snapshot.val();
console.log(data)
}, function(error) {
console.log(error);
});

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!

Update realtime database in Firebase

I am creating a API which can update value from realtime database (Firebase). Using ClaudiaJS to create API. Basically, API will update the number of student of a class by year.
What I have done:
Realtime Database (Firebase)
class
|__2015
| |__numberOfStudent: 50
|__2016
|__numberOfStudent: 60
Export to JSON like this:
{
"class": {
"2015": {
"numberOfStudent": 50
},
"2016": {
"numberOfStudent": 60
}
}
}
Javascript file (ClaudiaJS):
var ApiBuilder = require('claudia-api-builder');
api = new ApiBuilder();
module.exports = api;
var admin = require("firebase-admin");
var serviceAccount = require("./xxxxxxx-firebase-adminsdk-nxxxxx.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://xxxxxx.firebaseio.com"
});
api.post('/addmore/{year}/{number}', function (request) {
var database = admin.database().ref('class');
//Params
var year = request.pathParams.year;
var number = request.pathParams.number;
var ref = year + '/numberOfStudent'; // '2015/numberOfStudent'
database.update({
ref : parseInt(number) // "2015/numberOfStudent" : 60
});
return 'Update successfully';
});
When I run the api in Postman:
http://xxxxapi.com/addmore/2015/55
What happened: API replied 'Update successfully', but the database didn't get any update. It seems that the code database.update() doesn't work at all.
Any suggestion is very appreciated
The update call happens asynchronously, so currently the return happens before update completes.
update returns a Promise, so try the following:
return database.update({ref : parseInt(number)})
.then(() => {
// Each then() should return a value or throw
return 'Update successful';
})
.catch(error => {
// handle the error however you like
console.error(error);
});

How to pass data to angular app from setBackgroundMessageHandler() when using Firebase in Javascript?

I am using firebase in my angular app to send push notification in web.I implemented messaging.onMessage() for receiving notification when app is in foreground and messaging.setBackgroundMessageHandler() when app is in background.I receive notification without any problem but i need to update values based on the notification is received.I could do update when using messaging.onMessage() but how could we do that when using messaging.setBackgroundMessageHandler().
Even it will be ok if i can store the received value locally and get it in my app.
I did research on this is many places but i couldn't find any solution.
Can some one help me with this?
Thanks!
importScripts('https://www.gstatic.com/firebasejs/3.5.2/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.5.2/firebase-messaging.js');
var config = {
apiKey: "MY_API_KEY",
authDomain: "MY_AUTH_DOMAIN",
databaseURL: "MY_DB_URL",
storageBucket: "URL",
messagingSenderId: "VALID_ID"
};
firebase.initializeApp(config);
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
return self.registration.showNotification("Title", {body: 'New notification.',})
});
After searching for days found a Github page that contains a solution for it.
What you can do is get a list of window clients which will return a list of the tabs for your origin and then post a message to each window client. (This code would be in the setBackgroundMessageHandler()).
To get list of pages is:
const promiseChain = clients.matchAll({
type: 'window',
includeUncontrolled: true
})
.then((windowClients) => {
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
windowClient.postMessage(data);
}
})
.then(() => {
return registration.showNotification('my notification title');
});
return promiseChain;
Then to receive the message in the page, add a listener like so:
navigator.serviceWorker.addEventListener('message', function(event) {
console.log('Received a message from service worker: ', event.data);
});
Thanks alot guys who contributed in Github.
For more reference go to
https://web-push-book.firebaseapp.com/chapter-05/04-common-notification-patterns/#message-page-from-a-push-event
Hope it will be helpful for you guys.Ping or comment me if you get any doubts in implementing.

Categories