Rambo
Rambo

Reputation: 159

Parse can't find user record, then errors when trying to create it. Where did I go wrong?

I'm new to Parse and trying to wrap my head around promises at the same time. What I'd like to do is simply create a user in the DB if one doesn't exist and if one does exist I would update the row. The problem I am having is that my Parse.Query never finds the user row and then when it fails to find the row, it then fails to create a new user because the row exists. I know this is because either I need to force the method to wait for the search to return or to return a promise to be executed when the query returns, but I cannot figure out how to do it.

My current code is:

Parse.Cloud.define("findUser2", async req => {
  var phoneNumber = req.params.phoneNumber;
  phoneNumber = phoneNumber.replace(/\D/g, '');

  console.log("Incoming phone number is: " + phoneNumber)

  var userQuery = new Parse.Query(Parse.User);
  userQuery.equalTo('username', phoneNumber);

  var user = await userQuery.first();
  if(user) {
    console.log("Found a user, user is: " + user);
    //Validation stuff goes here
  } else {
    console.log("Did not find a user, create and return it");
    var newUser = new Parse.User();
    newUser.setUsername(phoneNumber);
    newUser.setPassword(secretPasswordToken + phoneNumber);
    newUser.set("language", "en");
    newUser.setACL({});
    newUser.save();
    //If this is not commented out, fails with:
    //Error: Cannot create a pointer to an unsaved ParseObject
    //user = newUser;
  }
  console.log("about to return the user");
  return user;
});

The output then returns:

app[web.1]: Incoming phone number is: 5555551212
app[web.1]: Did not find a user, create and return it
app[web.1]: about to return the user
app[web.1]: info: Ran cloud function findUser2 for user undefined with:
app[web.1]: Input: {"phoneNumber":"5555551212"}
app[web.1]: Result: undefined {"functionName":"findUser2","params":{"phoneNumber":"5555551212"}}
app[web.1]: error: Parse error: Account already exists for this username. {"code":202,"stack":"Error: Account already exists for this username.\n    at /app/node_modules/parse-server/lib/RestWrite.js:567:13\n    at processTicksAndRejections (internal/process/task_queues.js:85:5)"}
app[web.1]: (node:23) UnhandledPromiseRejectionWarning: Error: Account already exists for this username.

Based on the ordering of the logs, I know it is exiting the function before it completes the query. I thought the await would force it to not continue until this query returns or times out, thereby being able to fulfill the promise. It seems like I am wrong though and I am unsure how to resolve the issue.

Ideally I'd use Promises because I'd allow my code to run more efficiently, but I have await in for now because I was hoping it would make it simpler to get it working and be fine for a prototype. I'm looking for a good path forward and if the right approach is to return a promise, I'd like to know.

Upvotes: 0

Views: 165

Answers (1)

Davi Macêdo
Davi Macêdo

Reputation: 2984

Your cloud code function is returning before the new user is actually saved. You just need to await for it before returning. It would be something like this:

Parse.Cloud.define("findUser2", async req => {
  var phoneNumber = req.params.phoneNumber;
  phoneNumber = phoneNumber.replace(/\D/g, '');

  console.log("Incoming phone number is: " + phoneNumber)

  var userQuery = new Parse.Query(Parse.User);
  userQuery.equalTo('username', phoneNumber);

  var user = await userQuery.first({ useMasterKey: true });
  if(user) {
    console.log("Found a user, user is: " + user);
    //Validation stuff goes here
  } else {
    console.log("Did not find a user, create and return it");
    var newUser = new Parse.User();
    newUser.setUsername(phoneNumber);
    newUser.setPassword(secretPasswordToken + phoneNumber);
    newUser.set("language", "en");
    newUser.setACL({});
    await newUser.save(); //This is the line you need to change
    //If this is not commented out, fails with:
    //Error: Cannot create a pointer to an unsaved ParseObject
    //user = newUser;
  }
  console.log("about to return the user");
  return user;
});

Upvotes: 1

Related Questions