I am using the firebase admin sdk with bubble as a nodejs project
here is the code i am trying. THIS doesn't work. I have included updated code at the bottom but will leave this for now hoping others can learn from my errors.
function(properties, context) {
console.log('trying')
var list = []
var util = require("util")
var admin = require('firebase-admin');
var serviceAccount = <COPIED/PASTED FROM FIREBASE>
// Fetch the service account key JSON file contenT
if (admin != null) {
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://login-database-brc.firebaseio.com"
})
list.push('logged into app')
var db = admin.database();
var ref = db.ref('BRC/4jV39aEK6jOecLdKONJMKatsEYn1/data')
ref.once('value').then((snapshot) => {
snapshot.val().forEach(element => {
list.push('check')
list.push(element.Name)
})
});
} else {
list.push('nothing happened')
}
// As an admin, the app has access to read and write all data, regardless of Security Rules
return {
data: list
}
}
here are the rules
{
"rules":{
"BRC": {
"$uid":{
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
I only end up seeing 'logged in' in the output list. I would expect to see the name property from each object in the data bucket.
I am able to make this work fine client side using the standard sdk, and using password authentication. I can’t seem to get beyond initializing the apps Firebase instance.
i do have /BRC with rules that require authentication, but with the server SDK i didnt think this mattered
I want to access all ojects held within BRC/4jV39aEK6jOecLdKONJMKatsEYn1/data
[UPDATED CODE TO PERFORM OPERATIONS SYNCRONOUS]
function(properties, context) {
var serviceAccount = {'jsonObjectFromFirebase'};
var list =[];
var admin = require("firebase-admin");
// Initialize the app with a service account, granting admin privileges
if (!admin.apps.length){
initializeApp(serviceAccount)
};
// As an admin, the app has access to read and write all data, regardless of Security Rules
admin.database().ref('test').once('value')
.then((snapshot) => {
snapshot.val().forEach(element => {
let a = element.name;
list.push(a);
})
return_data(list)
});
function return_data (list){
return { data: list};
};
function initializeApp (serviceAccount){
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://thunkableproject-f51d9-default-rtdb.firebaseio.com"
});
}
}
the issue is that now return_data is never called. so I'm not sure what's happening here.
[update 2, trying again to create a synchronous call
var list =[]
var admin = require("firebase-admin");
// Initialize the app with a service account, granting admin privileges
if (!admin.apps.length){
initializeApp(serviceAccount)
}
// As an admin, the app has access to read and write all data, regardless of Security Rules
admin.database().ref('BRC/4jV39aEK6jOecLdKONJMKatsEYn1/data').once("value", function(snapshot){
let element = snapshot.val()
let list = []
for (var key in element) {
list.push(element[key].Name)
}
return_data(list)
})
function return_data (list){
return { data: list}
}
function initializeApp (serviceAccount){
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://login-database-brc.firebaseio.com"
});
}
I have also tried this to no avail
var promise = admin.database().ref('BRC/4jV39aEK6jOecLdKONJMKatsEYn1/data').once("value");
promise.then(snapshot => {
let element = snapshot.val()
let list = []
for (var key in element) {
list.push(element[key].name)
};})
.catch(error => {
alert(error)
});
return { data: list}
I think I now am calling this function in an asynchronous way that should wait for a callback. the issue now is that the code in the .then() never executes.
function getData() {
var promise = admin.database().ref('BRC/4jV39aEK6jOecLdKONJMKatsEYn1/data').once("value");
promise.then(snapshot => {
let element = snapshot.val()
let list = []
for (var key in element) {
list.push(element[key].Name)
};
return list;
})
.catch(error => {
return error
});
return promise;
}
getData().then((list) => {
return { "data": list }
})
The problem is that your return { data: list }
runs before the list.push(element.Name)
happens. This is because data is loaded from Firebase asynchronously, and runs out of the order you may expect. This behavior is the same on both client and server-side SDKs, and in most cloud based APIs you'll find these days.
The typical solution is to return a promise, instead of the actual value. Instead of explaining it here, I recommend reading these:
Edit:
In your edit, you have to return the promise. For example in function defined like this:
function getData() {
var promise = admin.database().ref('BRC/4jV39aEK6jOecLdKONJMKatsEYn1/data').once("value");
promise.then(snapshot => {
let element = snapshot.val()
let list = []
for (var key in element) {
list.push(element[key].name)
};
return list;
})
.catch(error => {
alert(error)
});
return promise;
}
Now you can use this function like this:
readData().then((list) => {
console.log(data);
})
Note that (as said in the comments) this does not make the code synchronous, as that isn't possible. It merely returns the promise to the caller, which then "waits" with then
for the data to be available.
If you're on a modern enough platform, you may be able to use await
in that last snippet:
var list = await readData();
console.log(data);
But while this may look more familiar, it still does the exact same thing behind the scenes and is not synchronous.