1

I have a functioning React Native Expo App that interacts with my Firebase Realtime Database. In short, I am stumped trying to find a means of checking across all child values to see if a value exists, before writing that value (again) as a new record to the database.

I historically have been getting "ExponentPushToken" from Expo's Push Notification API within my App.js and then immediately writing a new record to my Firebase Realtime Database using the following code within the same function for registering for Push Notifications from Expo's Push Notification API:

      const token = (await Notifications.getExpoPushTokenAsync()).data;
      console.log(token);
      var userListRef = firebase.database().ref("users/push_token");
      var newUserRef = userListRef.push();
      newUserRef.set(token);

I also have the following code reading the database and logging to console the correct information I need to be able to compare all of the outputted values to the aforementioned "token" value:

var userListRef = firebase.database().ref("users/push_token");
  userListRef.on("value", function (snapshot) {
    snapshot.forEach(function (child) {
      console.log(child.val());
    });
  });

Where I continue to hit a wall is in trying to take the acquired "token" and confirm that it is not already a "child.val()" (an existing value across the db) in my Firebase Realtime DB before I .push() and .set() to create a new record in said DB. I'd love to be able to log to console to verify too. The code below does not work... My attempt here is to try to .push() to an array and see if the "token" is somewhere in the array. This is happening but my last function with the "if/else" statement is is still looping for each record in the database. Not sure how to write this without looping the subsequent functions for every record in the database.

      const token = (await Notifications.getExpoPushTokenAsync()).data;
      console.log(token);
      var userListRef = firebase.database().ref("users/push_token");
      userListRef.once("value", function (snapshot) {
        snapshot.forEach(function (child) {
          createPushTokenArray(child.val());
          myTokenHandler(token);
        });
      });

  var allPushTokens = [];
  async function createPushTokenArray(dbState) {
    allPushTokens.push(dbState);
    return;
  }

  async function myTokenHandler(myToken) {
    await createPushTokenArray();
    var checkForValue = allPushTokens.includes(myToken);
    if (checkForValue === true) {
      return console.log("Push Token already stored in database.");
    } else {
      var userListRef = firebase.database().ref("users/push_token");
      var newUserRef = userListRef.push();
      var writeNewToken = newUserRef.set(myToken);
      writeNewToken;
      return console.log("New Push Token stored in database.");
    }
  }

My numerous attempts to try to get anywhere in all of this have been futile. For reference, here is the db structure below (in JSON format):

{
  "users" : {
    "push_token" : {
      "key or name" : "value",
      "-Maer1EuNpR24LdhxmIl" : "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]",
    }
  }
}

1 Answers1

1

I was able to figure it out myself actually, for anyone who was interested. It's probably not the cleanest way to do it, but the outcome is producing exactly what I needed.

Rather than running the unstoppable forEach() loop, I just grabbed the entire database, and then later defined it, and pulled ONLY the values.

See the code below that effectively checks to if all values across the DB includes our particular value.

      const token = (await Notifications.getExpoPushTokenAsync()).data;
      console.log(token);
      //---The above sits inside of a function. It is Expo's code for expo-notifications api----///
      var userListRef = firebase.database().ref("users/push_token");
      userListRef.once("value", function (snapshot) {
        createPushTokenArray(snapshot.val());
        myTokenHandler(token);
      });
      //---More code here to close function(s) and complete expo-notificaions api integration for Push Notifications---///
  var allPushTokens = [];
  function createPushTokenArray(dbState) {
    const defineDb = new Object(dbState);
    const newState = Object.values(defineDb);
    allPushTokens.push(newState);
  }
  async function myTokenHandler(myToken) {
    await createPushTokenArray();
    const cleanSearch = allPushTokens.values();
    for (const allData of cleanSearch) {
      console.log(allData);
      var checkForValue = allData.includes(myToken);
      if (checkForValue == true) {
        console.log("Push Token already stored in database.");
        break;
      } else {
        var userListRef = firebase.database().ref("users/push_token");
        var newUserRef = userListRef.push();
        var writeNewToken = newUserRef.set(myToken);
        writeNewToken;
        console.log("New Push Token stored in database.");
        break;
      }
    }
  }

It works like this:

  1. Get a "snapshot" of entire Firebase Realtime DB and create callbacks for query output AND my device's "token":
      var userListRef = firebase.database().ref("users/push_token");
      userListRef.once("value", function (snapshot) {
        createPushTokenArray(snapshot.val());
        myTokenHandler(token);
      });
  1. Create function to define the above output as an Object and then ONLY grab the values (remove the keys) AND make a global variable (allPushTokens) that will create a new array with just the object values. The output here is still a bit messy, so we'll break it down further to make it useful in step three.
  var allPushTokens = [];
  function createPushTokenArray(dbState) {
    const defineDb = new Object(dbState);
    const newState = Object.values(defineDb);
    allPushTokens.push(newState);
  }
  1. Lastly, create an async function that calls back to my device's "token", waits for the previous function to create a newly defined array for us, and then parses the newly defined array to include only the arrays values using allPushTokens.values(); which gives us an output that's readable and useful for us compare to my devie's "token". We then use for-of to begin looping through the data until our criteria is met: (if) my device's "token" is included somewhere the values within my database, stop the loop, (else/then) proceed to write my device's "token" to the database.
  async function myTokenHandler(myToken) {
    await createPushTokenArray();
    const cleanSearch = allPushTokens.values();
    for (const allData of cleanSearch) {
      console.log(allData);
      var checkForValue = allData.includes(myToken);
      if (checkForValue == true) {
        console.log("Push Token already stored in database.");
        break;
      } else {
        var userListRef = firebase.database().ref("users/push_token");
        var newUserRef = userListRef.push();
        var writeNewToken = newUserRef.set(myToken);
        writeNewToken;
        console.log("New Push Token stored in database.");
        break;
      }
    }
  }