Avoid creating new record for same user?

Hi all! I have a Javascript integration question

I apologize if this is basic, I am quite new here. I have created a Discord bot that is storing game win rate stats using an Airtable base. Each user on Discord has a unique ID which I am storing in the first column of the table. I have a function on my bot that allows users to add themselves to the base by creating an entry with their Discord ID and with their number of games played and won. I don’t want to have two records for the same user, however, so I want to add a logical check that searches my base to see if there is already a record wherein the discordID column matches the ID of the user attempting to be added to the base.

Basically, if my discordID is 222, I want to search my base for entries where the discordID is 222, and if more than 0 appear then I want to NOT add myself, but if 0 results are returned then I DO want to add myself.

I have tried doing this below, but it doesn’t seem to be working as expected (i.e. my console will log “duplicate found” but it will still add the user to my base:

let userCount = 0;

client.base('data').select({
    filterByFormula: '{userID} = '+user.id
  }).eachPage(function page(records, fetchNextPage) {
    records.forEach(function(record) {
      userCount += 1;
      console.log("duplicate found");
    })
  }, function done(error) {
    console.log('error');
    return;
  });

if(userCount === 0) {
  client.base('data').create([
      {
        "fields": {
          "userID": user.id,
          "gamesPlayed": 0,
          "gamesWon": 0,
          "gamesPlayedBlue": 0,
          "gamesWonRed": 0,
          "gamesPlayedRed": 0,
          "gamesWonBlue": 0
        }
      }
  ], function(err, records) {
      if (err) {
        console.error(err);
        return;
      }
      records.forEach(function (record) {
        console.log(record.getId());
      });
    });
} else {
  message.channel.send("This user's stats are already being tracked in the database!");
}

If anyone is able to help, I would be very appreciative; thank you all!

Warmly,
Spence

Hi Spence,

The most important detail which is missing from your code is that the eachPage function is asynchronous. I’ll share an updated version that addresses this, and then I’ll explain why it’s important.

solution (click to expand)
 let userCount = 0;
 
 client.base('data').select({
     filterByFormula: '{userID} = '+user.id
   }).eachPage(function page(records, fetchNextPage) {
-     records.forEach(function(record) {
-       userCount += 1;
-       console.log("duplicate found");
-     })
+     userCount += records.length;
+     fetchNextPage(); // Don't forget to call this function as per the documetation
   }, function done(error) {
+    if (error) {
       console.log('error');
       return;
+    }
+    if (userCount > 0) {
+      message.channel.send("This user's stats are already being tracked in the database!");
+    } else {
+      create();
+    }
   });
 
-if(userCount === 0) {
+function create() {
   client.base('data').create([
       {
         "fields": {
           "userID": user.id,
           "gamesPlayed": 0,
           "gamesWon": 0,
           "gamesPlayedBlue": 0,
           "gamesWonRed": 0,
           "gamesPlayedRed": 0,
           "gamesWonBlue": 0
         }
       }
   ], function(err, records) {
       if (err) {
         console.error(err);
         return;
       }
       records.forEach(function (record) {
         console.log(record.getId());
       });
     });
-} else {
-  message.channel.send("This user's stats are already being tracked in the database!");
 }

eachPage is asynchronous. You call it with a function, and the airtable.js library immediately makes a request to Airtable’s servers to retrieve the data.

Once airtable.js has made a request (and before the response returns), the rest of your script continues to execute. That means

if (userCount === 0) {
  // etc.

runs before the response has arrived. The value of userCount will always be zero at this moment because (as fast as it may seem) the response never returns instantly.

Later, when the response arrives, airtable.js invokes the function you provided (the function named page in your example). At this point, changes to the userCount variable no longer make a difference because the code which relies on it has already executed.

One solution is to wrap the code which creates a record in a function, and then to only call that function once the response from Airtable’s servers arrives. That’s what’s going on in the modified version I shared above.