Usage of exec() method on create query - node.js

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
}
});

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.

Handling Callbacks in Classes

I'm building classes to find and quickly operate actions on mongodb documents. This is the UserCursor class. (Not talking about MongoDB's cursor)
exports { UserCursor };
class UserCursor {
private __id: object;
constructor(query: { _id?: object, otherId?: number }) {
let { _id, otherId } = query; // Shortens the vars' name
if (!_id && !otherId) return; // Checks if 1 identifier is provided
if (_id) { // If a _id is provided
Users.findOne({ _id }, (err, user) => {
this.__id = user._id;
});
} else if (otherId) { // If a otherId is provided
Users.findOne({ otherId }, (err, user) => {
console.log(1); // Debug, you'll see later
this.__id = user._id;
});
}
}
// Returns this.__id (which should have been initialized in the constructor)
get _id() {
console.log(2)
return this.__id;
}
}
When run, the console returns
2
1
I think you got the problem: the mongo callback in the constructor gets on after _id operates. How could I manage that, since the constructor gets activated each time the class is used?
It's not entirely clear to me, what exactly you want to happen and how you use this class but I assume you want to instantiate it and then be able to get _id instantaneously. If it's not the case, you may still get some useful info from my answer. Feel free to provide more details, I will update it.
So mongodb operations are asynchronous, if you do
const cursor = new UserCursor(...)
console.log(cursor._id)
(I assume you want this), first all operations in this thread will run, including the call to get _id(), then the callback code will. The problem with such asynchronous things is that now to use this _id you will have to make all of your code asynchronous as well.
So you will need to store a Promise that resolves with _id from mongodb and make a method getId that returns this promise like this:
private __id: Promise<object>
constructor(...) {
// ...
if(_id) {
this.__id = new Promise((resolve, reject) => {
Users.findOne({ _id }, (err, user) => {
if(err) return reject(err)
resolve(user._id)
});
})
} else {
// Same here
}
}
public getId() {
return this.__id;
}
Then use it:
const cursor = new UserCursor(...)
cursor.getId().then(_id => {
// Do smth with _id
})
Or
async function doStuff() {
const cursor = new UserCursor()
const _id = await cursor.getId()
}
doStuff()
If you now do it inside some function, you'll also have to make that function async
Also you could leave a getter like you have now, that will return a promise, but I find it less readable than getId():
cursor._id.then(_id => { ... })
const _id = await cursor._id

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

Mongoose document: Execute hook manually for testing

I'd like to test some document transformation which is executed in a Mongoose pre save hook. Simplified example:
mySchema.pre('save', function(callback) {
this.property = this.property + '_modified';
callback();
});
Test:
var testDoc = new MyDocument({ property: 'foo' });
// TODO -- how to execute the hook?
expect(testDoc.property).to.eql('foo_modified');
How can I manually execute this hook?
Okay, here’s what we did at the end. We replaced the $__save function with a no operation implementation:
// overwrite the $__save with a no op. function,
// so that mongoose does not try to write to the database
testDoc.$__save = function(options, callback) {
callback(null, this);
};
This prevents hitting the database, but the pre hook obviously still gets called.
testDoc.save(function(err, doc) {
expect(doc.property).to.eql('foo_modified');
done();
});
Mission accomplished.
As of Mongoose 5.9, using the $__save override doesn't seem to work, so here is a replacement that doesn't require you to call the save() method directly:
const runPreSaveHooks = async (doc) => {
return new Promise((resolve, reject) => {
doc.constructor._middleware.execPre("save", doc, [doc], (error) => {
error ? reject(error) : resolve(doc);
});
});
};
await runPreSaveHooks(testDoc);
expect(testDoc.property).to.eql('foo_modified');

Node.JS Mongodb query / create

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.

Resources