1

For an AppInventor app which uses Firebase as database, I want to give unique user IDs to app users. After looking for some options I had the idea that I could use a Cloud HTTP function to be requested by the app, and the returning data would be a UserId generated by simply incrementing the last UserId in the UserIds table (not sure if it is one, either).

That's the story, but I can't make the following code to deploy (and when I can, it doesn't work as I expect). It reads the last UserId correctly, but I could only make it overwrite the previous data so far.

It throws an unexpected token error in the "." in functions.https.

const functions = require('firebase-functions');
// Import and initialize the Firebase Admin SDK.
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

var LastUserId = function f() {return admin.database().ref('UserIds').limitToLast(1)}

exports.addWelcomeMessages = functions.https.onRequest((request, response)) => {
    var ref = admin.database().ref('UserIds');
    // this new, empty ref only exists locally
    var newChildRef = ref.push();
    // we can get its id using key()
    console.log('my new shiny id is '+newChildRef.key());
    // now it is appended at the end of data at the server
    newChildRef.set({User : LastUserId + 1});
});
Grimthorr
  • 6,856
  • 5
  • 41
  • 53
Ugur
  • 312
  • 5
  • 15

1 Answers1

1

The Firebase Authentication package provides an automatically generated unique ID for every authenticated user already, which you can obtain from firebase.auth().currentUser.uid on web and similar methods for other platforms.

If you still want to generate your own incremental ID using Cloud Functions, you'll need to make use of a transaction and then send back the new ID, something like:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.generateUserId = functions.https.onRequest((req, res) => {
    var ref = admin.database().ref('/lastUserId');
    ref.transaction(function(current) {
      return (current || 0) + 1;
    }, function(error, committed, snapshot) {
      if (error || !committed || !snapshot) {
        console.error("Transaction failed abnormally!", error || "");
      } else {
        console.log("Generated ID: ", snapshot.val());
      }
      res.status(200).send(snapshot.val().toString());
    });
});

This increments the lastUserId value in the database using a transaction and then sends this new ID back as a response (using res.send()) for use in the calling app.

Grimthorr
  • 6,856
  • 5
  • 41
  • 53
  • does this write to the database as well as I'm trying to do here: `newChildRef.set({User : LastUserId + 1});` – Ugur Nov 09 '17 at 12:11
  • Yes, the transaction will write back to the same location any value that is returned, so `return (current || 0) + 1;` will increment the current value by 1 (starting at 0 if `lastUserId` doesn't exist) and then save it back to the database automatically. – Grimthorr Nov 09 '17 at 12:13
  • Database is written ok, but I'm getting error in the logs and it doesnt return the written data: `TypeError: Cannot read property 'val' of undefined at admin.database.ref.transaction.then (/user_code/index.js:15:38) at process._tickDomainCallback (internal/process/next_tick.js:135:7)` any ideas? – Ugur Nov 09 '17 at 13:10
  • Oops, sorry that's my fault, I didn't actually test the code! See updated code which I've reworked & tested. – Grimthorr Nov 09 '17 at 14:51
  • What you could also consider, is using GUID / UUIDs - They have some benefits in terms of creating them prior insertion time. You can read some more about it here https://stackoverflow.com/questions/45399/advantages-and-disadvantages-of-guid-uuid-database-keys – Dennis Nov 09 '17 at 14:53