I am currently trying to implement an update / put functionality in my node.js-project and having issues I have absolutely no clue, where that comes from. (also I am a JS beginner). I am using express, MongoDB and mongoose.
Problem is in this method (or how I call it):
User.findOne({ userID: searchUserID })
Kontext of the the method, that is called:
/* find User by userID */
// calling sequence: UserService > findUserBy() callback
function findUserBy(searchUserID, callback) {
logger.debug(`UserService: searching for user with userID '${searchUserID}'...`)
let query = User.findOne({ userID: searchUserID })
query.exec(function (err, user) {/*content*/})
}
When I call it directly from the UserRoute module like this:
/* get one user */
// calling sequence: UserRoute > router.get('/:userID') callback > userService.findUserBy() callback
router.get('/:userID', function (req, res, next) {
userService.findUserBy(req.params.userID, function (err, user) {/* content */})
})
then it all works fine.
But when I want to use that function from another function inside the same module (UserService
):
/* update one User */
// calling sequence: UserService > updateUser > findUserBy() callback
function updateUser(userID, newUserData, callback) {
findUserBy(userID, function (err, user) {...})
let id = user.body.id
/* more content */
}
Then I am getting an error, since ‘user’ is not defined.
Obviously User.findOne({ userID: searchUserID })
is working in the first case and returns a user. But it is not working in the second case.
I have used the debugger to check the parameters, that are delivered when calling the findOne function.
The 1st parameter is: searchUserID
and the value is: ‘manfred’
The 2nd parameter is a callback function, but it doesn’t come this far anyway.
The first parameter is exactly the same, no matter whether I call it directly from UserRoute.js
or the UserService.js
.
I have also compared the content of the ‘query’-objects in both cases.
It has a bit more then 3700 lines and they have differences in like 10 lines… some veeeery long numbers that I don’t understand. Probably random Numbers, timeStamps or …I really have no clue (but if someone needs them I can look them up again).
Why is User.findOne({ userID: searchUserID })
not working in the second case?
EDIT: my full functions (without shortening them with ‘content)
in UserService.js
:
//find User by userID
function findUserBy(searchUserID, callback) { //UserService > findUserBy() callback
logger.debug(`UserService: searching for user with userID '${searchUserID}'...`)
let query = User.findOne({ userID: searchUserID }) // query object erstellen
query.exec(function (err, user) { //query wird asynchron ausgeführt
if (err) {
logger.error(err.message)
return callback(err.message) // callback übergibt fehlernachricht
}
if (user) { // hier wirkt null wie false
logger.debug(`Found userID: ${searchUserID}`)
callback(null, user)
}
else {
//logger.error("Did not find user for userID: " + searchUserID)
callback(`Did not find user with userID: ${searchUserID}`, user) // callback übergibt fehlernachricht
};
})
}
This one is not done yet, but that comes after:
// update User
function updateUser(userID, newUserData, callback) {
logger.debug(`Updating user '${userID}'...`)
findUserBy(userID, function (err, user) { //UserService>updateUser>findUserBy() callback
if (user) {
logger.debug(user)
(null, user.body)
}
else {
logger.error(err)
return console.log("Did not find any User with this userID" + [], null)
}
})
//logger.debug("user:" + user, err)
console.log("so far so good...")
let id = user.body.id
let user = new User()
Object.assign(user, user.body)
Object.assign(user, newUserData)
user.body.id = id
user.save(function (err) {
if (err) {
logger.debug("Could not create user account: " + err)
return callback("Could not create user account", null)
}
else {
callback(null, user)
}
})
}
in UserRoute.js
:
/* update one User */
router.put('/:userID', function (req, res, next) {
userService.updateUser(req.params.userID, req, function (err, user) {
if (user) {
//res.send(Object.assign(user))
logger.debug(user)
res.send(`User ${req.body.userID} sucessfully updated. rr new Json-Body: r ` + user)
}
else {
logger.error(err)
res.send("Did not find any User with this userID" + [])
}
})
})
/* get one user */
router.get('/:userID', function (req, res, next) {
userService.findUserBy(req.params.userID, function (err, user) { //UserRoute > router.get('/:userID') callback > userService.findUserBy() callback
if (user) {
res.send(user)
logger.debug(user)
//res.json(user)
}
else {
logger.error(err)
res.send("Did not find any User with this userID" + [])
}
})
})
2
Answers
you need to convert req.params.userID to an object Id
For eg :
Types.ObjectId(req.params.uuid)
also Import Types
It does not work because you try to access the data while you still fetching it from the DB.
My opinion: Dont use callbacks, they are pretty old and you will sooner or later land into an callback hell. Mongoose supports Promises. Rewrite your code a bit:
If you not provide an callback, your function will return an promise with either
null
or your user.Lets rewrite your router a bit:
I made an
async / await
out of it.await
only works in an async function and can await Promises.If you do this now:
You should see some result. I made
updateUser
an async function. So you can useawait
. But watch out. Async function returns an promise, so you will also need to useawait
on them.If you ever see an callback as second argument, then its most of the time asynchronouse code.
Edited code: