16

I am using Flutter to build an app that accesses the Firebase database. All good from the Flutter side....but I am new to Node.js and Cloud Functions. I am trying to create a Node.js function to react to a deletion event of a record on one Firebase Database node and then delete records from two other Firebase Database nodes and image files from Firestore.

I am reacting to the trigger event with a functions.database.onDelete call, no problem, but falling at the very next hurdle i.e.trying to read admin.database to get a snapshot.

I have created a dummy function that uses .onUpdate to pick up a trigger event (don't want to keep having to recreate my data as I would if I used .onDelete) and then tries to read my Firebase Database to access a different node. The trigger event is picked up fine but I don't seem to have a database reference Url to do the read...yet it is the same database. Output on the console log from a call to process.env.FIREBASE_CONFIG shows the Url is present.

The included function code also has commenting to show the various outputs I get on the console log.

I am going crazy over this.....PLEASE can anyone tell me where I am going wrong. Been searching Google, Stackoverflow, Firebase docs for the last two days :-(


const admin = require("firebase-admin"); // Import Admin SDK
const functions = require("firebase-functions"); // Import Cloud Functions

admin.initializeApp({
  credential: admin.credential.cert(
    require("./user-guy-firebase-adminsdk.json")
  )
});

exports.testDeleteFunction = functions.database
  .ref("/user-guys/{userGuyId}")
  // Using .onUpdate as I don't want to keep restoring my data if I use .onDelete
  .onUpdate((snapshot, context) => {

    const userData = snapshot.after.val();
    const userId = userData.userId;

    console.log('userId: ' + userId);         // Gives correct console log output: userId: wajzviEcUvPZEcMUbbkPzcw64MB2

    console.log(process.env.FIREBASE_CONFIG);
    // Gives correct console log output:
    // {"projectId":"user-guy","databaseURL":"https://user-guy.firebaseio.com","storageBucket":"user-guy.appspot.com","cloudResourceLocation":"us-central"}


    // I have tried each of the four following calls and received the console log message as indicated after each.
    // 
    // var root = admin.database.ref();       // Console Log Message: TypeError: admin.database.ref is not a function
    // var root = admin.database().ref();     // Console Log Message: Error: Can't determine Firebase Database URL.
    // var root = admin.database.ref;         // Fails at line 31 below with the message indicated.
    // var root = admin.database().ref;       // Console Log Message: Error: Can't determine Firebase Database URL.

    console.log(root.toString);               // Console Log Message: TypeError: Cannot read property 'toString' of undefined.

    // This is intended to read a chat thread for two users but processing never gets here.
    var database = root.child('chats').child('0cSLt3Sa0FS26QIvOLbin6MFsL43GUPYmmAg9UUlRLnW97jpMCAkEHE3');

    database
      .once("value")
      .then(snapshot => {
        console.log(snapshot.val());
      }, function (errorObject) {
        console.log("The read failed: " + errorObject.code);
      });
    return null; // Will do stuff here once working.
  });

Error messages shown in code comments.

Libu Mathew
  • 2,976
  • 23
  • 30
GrahamD
  • 2,952
  • 3
  • 15
  • 26
  • You have a second problem in your code as well. You're not returning a promise that resolves when all the async work is complete. – Doug Stevenson Jun 12 '19 at 16:25

5 Answers5

8

If you want to use the configuration in FIREBASE_CONFIG, you should initialize the Admin SDK with no parameters:

admin.initializeApp();

This will use the default service account for your project, which should have full read and write access to the database.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • @zhoki and Dave, thanks very much for your rapid responses...much appreciated! – GrahamD Jun 12 '19 at 18:18
  • 5
    This is not the full solution though because the params in the initialization script are used by other functions in the real index.js e.g.private keys, auth ids, certs. So I have to have a params in the final version. I tried adding `databaseUrl` to the script but didn't help so need to do more research. Any ideas on running this with initialization parameters? – GrahamD Jun 12 '19 at 18:25
  • the missing bit is that I will use your solutions to take this further and test. Thnaks again – GrahamD Jun 12 '19 at 18:26
  • I intend to return a call to delete the chat thread as the final statement so that should sort out the promise issue, correct? – GrahamD Jun 12 '19 at 18:29
5

You need to add your database url in admin.initializeApp

 admin.initializeApp({
 databaseURL:"your_database_url"
  });
Manik
  • 153
  • 4
  • 15
5

select Realtime Database in firebase and copy your url add in settings in fire config or watch this video https://www.youtube.com/watch?v=oOm_9y3vb80

config example

const config = {
  apiKey: "",
  authDomain: "",
  projectId: "",
  databaseURL: "https://youUrl.firebaseio.com/",
  storageBucket: "",
  messagingSenderId: "",
  appId: "",
  measurementId: ""
};
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
2060fw4r
  • 51
  • 1
  • 1
2

Same issue 3 years later...

After DAYS! I found out all of the Flutter documents have code for Firestore instead of Firebase.

Basically there are two products. Firestore Database, and Real-time Database. You are calling the Real-time Database methods, but probably have a Firestore database.

Try admin.firebase().ref('/some_collection').push();

Basically everywhere you're calling .database(), replace it with .firebase() if you are using Firebase. Yes, the Flutter tutorials are mis-leading!!!

1

See:

Try initialize without parameters.

The SDK can also be initialized with no parameters. In this case, the SDK uses Google Application Default Credentials and reads options from the FIREBASE_CONFIG environment variable. If the content of the FIREBASE_CONFIG variable begins with a { it will be parsed as a JSON object. Otherwise the SDK assumes that the string is the name of a JSON file containing the options.

const admin = require("firebase-admin"); // Import Admin SDK
const functions = require("firebase-functions"); // Import Cloud Functions

admin.initializeApp();
zkohi
  • 2,486
  • 1
  • 10
  • 20