0

I currently have a check I'm running to see if a username is taken or not. I am querying to see if the username has been taken, and if so provide a value to my errors object. I want to pass my errors defined within my if statement to the outer return statement. Is there a way to go about this?? Im unsure of what to do here.

exports.reduceUserDetails = data => {
  let errors = {}
  const userRef = db.collection('users').where('username', '==', data.username)
  userRef.get().then(snapshot => {
    if (!snapshot.empty) {
      errors.username = 'username taken'
    } else {
      console.log('im not taken')
    }
  })
  return {
    errors,
    valid: Object.keys(errors).length === 0 ? true : false
  }
}

here is where I'm using the reduce user details:

exports.profileUpdate = (req, res) => {
  let userDetails = req.body
  const { valid, errors } = reduceUserDetails(userDetails)
  if (!valid) return res.status(400).json(errors)

  let document = db
    .collection('users')
    .where('username', '==', req.user.username)
  document
    .get()
    .then(snapshot => {
      snapshot.forEach(doc => {
        const data = doc.id
        db.collection('users').doc(data).update(req.body)
      })
      res.json({ message: 'Updated Successfully' })
    })
    .catch(error => {
      console.error(error)
      return res.status(400).json({
        message: 'Cannot Update the value'
      })
    })
}
Rob Terrell
  • 301
  • 2
  • 11
  • The problem is not with scoping. The problem is that `userRef.get()` is `async`, which means that the data is `returned` before the `async` request finishes. You'll have to move the `return` inside the `.then()` callback. – Amar Syla Jul 27 '20 at 14:54
  • could you possibly provide me with an example of how to do so. Unsure of how to go about this – Rob Terrell Jul 27 '20 at 14:57
  • Please see [How do I return the response from an aynchronous call](https://stackoverflow.com/q/14220321/438992), which this duplicates. – Dave Newton Jul 27 '20 at 14:59
  • @AmarSyla this issue is I need to be able to access errors outside of the .then callback is there a way to do this – Rob Terrell Jul 27 '20 at 15:08

1 Answers1

0

May be abstracting the call in a new function and awaiting it in caller might work, otherwise you will need to add await before reduceUserDetails() wherever you will call

exports.reduceUserDetails = async data => {
        
        let check = await dupChk(data);
        return {
            check.errors,
            valid: check.result
        }

}


var dupChk = (data) => (
    new Promise((resolve, reject) => {
     
        let errors = {}
        const userRef = db.collection('users').where('username', '==', data.username)

        userRef.get().then(snapshot => {

            if (!snapshot.empty) {
                errors.username = 'username taken'
                resolve({result:false,errors:errors})
            } else {
                resolve({result:true, errors: errors});//console.log('im not taken')
            }

        })

    })
);

UPDATE:

Ok no need to do the above stuff just change the reduceUserDetails() like this

exports.reduceUserDetails = data => {
        
    return new Promise((resolve, reject) => {
        let errors = {}
        const userRef = db.collection('users').where('username', '==', data.username)

        userRef.get().then(snapshot => {
            if (!snapshot.empty) {
                errors.username = 'username taken'
                resolve({valid:false,errors:errors})
            } else {
                resolve({valid:true, errors: errors});//console.log('im not taken')
            }
        })
        .catch(()=>resolve({result:false,errors:errors}))
    })

}

And in profileUpdate() add await keyword before the reduceUserDetails() call

const { valid, errors } = await reduceUserDetails(userDetails)
Viney
  • 6,629
  • 3
  • 21
  • 40
  • I have updated my question to include where I am using the reduce user details. When I change that to asynchronous I get the following error: Error: Value for argument "value" is not a valid query constraint. "undefined" values are only ignored in object properties. – Rob Terrell Jul 27 '20 at 16:27
  • TypeError: Cannot destructure property `valid` of 'undefined' or 'null'. – Rob Terrell Jul 27 '20 at 16:52
  • Oops missed return there; should've been `return new Promise ......` also no need to declare `reduceUserDetails` as `async ` as we are returning promise so no need of another promise – Viney Jul 27 '20 at 16:54
  • this seems to be closer to what I need thank you so much. One question I have; however, is when i console.log(errors.username) in the profile update I get something back, but when I try to do the following if (!valid) return res.status(400).json(errors.username) the 400 does not fire – Rob Terrell Jul 27 '20 at 17:11
  • `valid` must be `true` then and `errors` equal to `{}`. Or may be some error must've happened try adding a catch (see update) – Viney Jul 27 '20 at 17:20
  • > Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client – Rob Terrell Jul 27 '20 at 17:32
  • that's what comes back when i add the catch – Rob Terrell Jul 27 '20 at 18:22
  • Somewhere must've missed a [return](https://www.codementor.io/@oparaprosper79/understanding-node-error-err_http_headers_sent-117mpk82z8) – Viney Jul 28 '20 at 03:54