Node.JS Mongodb query / create - node.js

I have the following Node.js javascript function:
const createOrUpdateProfile = (pProfile) => {
db.update({facebookId: pProfile.facebookId}, pProfile, {upsert:true}, function (err, profile) {
if (err) {
console.log(err);
};
console.log("profile " + profile.occupation);
return profile;
})
};
The function is called with a user profile object which is just an ordinary object with some user information. Nothing special there.
As a matter of fact the function does what i want it to do. It either finds the profile in the MongoDB database and updates it or it inserts it into the database if it's not found.
The problem is that the profile (new or updated is never returned. I guess it has something to do with the asynchronous nature of Node.
I'm already using a call back function to capture the profile but is doesn't seems to work.
what am I missing here?
EDIT:
I changed the function to look like you sugessted:
const createOrUpdateProfile = (pProfile, callback) => {
db.update({facebookId: pProfile.facebookId}, pProfile, {upsert:true}, function (err, profile) {
if (err) {
console.log(err);
};
callback(profile);
})
};
and i call it from a graphQL mutation like this:
createOrUpdateProfile: (_, { profile }) => {
Profile.createOrUpdateProfile(profile, (cbProfile) => {
// do something with the new profile
console.log(cbProfile.occupation);
})
},
but the cbProfile appears to be undefined.
Am I doing this wrong?
I will have to look into promises later. i just want to get this working first.
Kim

You can't return from an asynchronous call inside a synchronous function. Instead, you can use a callback. Like this:
const createOrUpdateProfile = (pProfile, callback) => {
db.update({facebookId: pProfile.facebookId}, pProfile, {upsert:true}, function (err, profile) {
if (err) {
console.log(err);
};
console.log("profile " + profile.occupation);
callback(profile);
})
};
Then you can call it like this:
createOrUpdateProfile(pProfile, (profile) => {
// do something with the new profile
console.log(profile);
})
If you don't want to use callbacks, then Promises are another way of achieving this functionality.

Related

NEDB NodeJS find document and wait for the result

I am using NEDB for some local storage in an NodeJS Application. Therefore I do have an handlerscript "nedbhandler.js" which I do require in my main.js.
var NEDB = require('./nedbhandler.js');
async function test(){
var value = await NEDB.getValue_byID(1);
console.log(value)
}
test()
while in the nedbhandler.js is my query handled like this:
async function getValue_byID(id){
db.config.findOne({ _id: id }, function (err, doc) {
callback(doc);
});
function callback(doc) {
console.log(doc)
return doc;
}
}
exports.getValue_byID = getValue_byID;
While the console from nedbhandler.js logs the expected value, the main.js still is undefined.
What would be the best practice to load all config querys before loading next function in the main.js?
You want your getValue_byID function to return a promise
function getValue_byID(id){
return new Promise((resolve, reject) => {
db.config.findOne({ _id: id }, (err, doc) => {
err ? reject(err) : resolve(doc);
});
});
}
Note how I changed the function keyword to the more modern => syntax.
It is also considered better practice to use const and let insteadof var
There is a wrapper module for nedb, called NeDB-promises. It does more or less what I have done here, so you can use async/await instead of callbacks.

NodeJS sqlite3 not returning variable (scope problem)

This code returns undefined when it should be data from the Database. It is part of a class which has the variable this.database (an sqlite3 database). What have I done wrong?
getData(chip_id) {
let user_name;
this.database.get("SELECT data FROM chips WHERE id=?",[chip_id],(err,row) => {
user_name = row.data;
});
return user_name;
}
Retrieving data from database is an asynchronous action and you should handle it with something like Promise or async function. Change your function to this.
getData(chip_id) {
return new Promise((resolve, reject) => {
let user_name;
this.database.get("SELECT data FROM chips WHERE id=?", [chip_id], (err, row) => {
if(err) {
reject(err);
}
else {
user_name = row.data;
resolve(user_name);
}
});
});
}
and in the client side:
getData(id)
.then(username => {
// the username is ready to use
})
.catch(error => {
// handle the error
});
Reading these links also helps you a lot to start:
Callbacks Vs Promises and basics of JS
Getting to know asynchronous JavaScript: Callbacks, Promises and Async/Await
Converting callbacks to promises

Usage of exec() method on create query

I have a situation where I want to put all the business logic and callbacks in one place and mongoose queries in one place. So I'm making use of .exec() method for that purpose and handle its callback in service module. I'm successful with find query with exec()
repository module:
const findAUser = userName => {
return Users.findOne({username: userName});
}
Service Module
repository.findAUser(user.username).exec((error, document) => {
console.log(document);
if(error) {
rejectGeneric(reject);
} else {
..............................
But i'm not able to achieve the same with create query of mongoose
const createAUser = user => {
return Users.create(user);
}
And the below code doesn't work
repository.createAUser(user).exec((error, document) => {
....................................
}
How to use exec() method on mongoose create query? Is there any way to achieve this?
I have solved this by using callback option, and my resolution looks like this:
repository
const createAUser = (user, callback) => {
return Users.create(user, (error, document) => callback(error, document));
}
Service
repository.createAUser(user, (error, document) => {
if(error) {
// Do stuff for error handling
} else {
// Do stuff for success scenario
}
});

Unable to use .then in express framework

I'm new to Express framework and learning, I'm having a problem using .then. The problem is I have 2 functions and I want the first one to complete before the second to start executing. I'm exporting the modules.
var ubm = require('./userBasic');
There are 2 functions setUserData and showUserId, the showUserId must execute only after setUserData has performed its operation.
var userId = ubm.setUserData(userName,userEmail,userDOB,moment);
userId.then(ubm.showUserId(userId));
Below are the 2 functions:
module.exports = {
setUserData: function (userName,userEmail,userDOB,moment){
//Performing database activities
return userId;
}
showUserId: function (userId){
console.log(userId);
}
}
When i run it says TypeError: Cannot read property 'then' of undefined.
Like I said I'm very new and learning and was unable to figure out the solution. I did some google search and got a brief about promise, but I don't know how to implement here.
Try using promises
module.exports = {
setUserData: function(userName, userEmail, userDOB, moment) {
return new Promise(function(resolve, reject) {
//db stuff
reject(error);
resolve(userId);
});
},
showUserId: function(userId) {
console.log(userId);
};
};
So in your execution you would write
ubm.setUserData(username, usereEmail, userDOB, moment)
.then((data) => {
showUserId(data);
})
.catch((err) => {
console.log(err);
});
A couple of things to note is that in this instance you could just log data without the need for another function like
ubm.setUserData(username, usereEmail, userDOB, moment)
.then((data) => {
console.log(data);
})
.catch((err) => {
console.log(err);
});
Whatever value you pass into resolve() will be returned as well as you pass errors into reject().

Using Waterline find method with promisses

I'm stuck when it comes to returning response, from method that includes database call.
Here's sample of what I need...
service.js
module.exports = {
getUserStatus: function(userId){
return User
.find()
.where({userId: userId)
.exec(function(err, user){
return user.status;
}
}
}
In this service.js, I should fetch user's status and if I console.log(user.status) inside exec method, that is printed OK (I got status).
The problem is I need this result outside service.js:
controller.js
// this code is extracted from longer file, just for demo purpose.
// userService is required 'service.js'
index: function(req, res) {
var status = userService.getUserStatus(req.session.User.id);
console.log(status);
return res.view({userStatus: status});
}
If I console.log(status) here, it will be undefined.
I guess that it has something to do with promises and stuff (because of the async calls), but not sure what is the right way to do it.
getUserStatus contains asynchronous code, so it needs a callback:
module.exports = {
getUserStatus: function(userId, cb){
User.findOne().where({userId: userId}).exec(function(err, user){
if (err) return cb(err);
return cb(null, user.status);
});
}
}
then in the code that uses it:
index: function(req, res) {
userService.getUserStatus(req.session.User.id, function(err, status) {
// If an error was returned from the service, bail out
if (err) {return res.serverError(err);}
console.log(status);
return res.view({userStatus: status});
});
}
Note the use of findOne instead of find; find will return an array.
An alternative would be to return a promise from the service function, and chain your controller code with .then() and .fail():
module.exports = {
getUserStatus: function(userId, cb){
return User.findOne().where({userId: userId});
}
}
index: function(req, res) {
userService.getUserStatus(req.session.User.id)
.then(function(user) {
console.log(user.status);
return res.view({userStatus: user.status});
})
.fail(function(err) {
return res.serverError(err);
});
});
}
It's a matter of preference, but I think the first method is better especially in your case, since it allows the service call to deliver just the status, rather than the whole user object. In general, getting used to the standard (err, result) callback method in Node will serve you well.

Resources