Having problems exporting model functions (Express and Mongoose) - node.js

I have been looking at code (https://github.com/cmarin/MongoDB-Node-Express-Blog) to learn NodeJS, Express, Mongoose, and I am having trouble importing a 'Poll' function from my 'models.js' file, particularly the 'save' function.
I am getting the following error:
500 TypeError: Object function (){} has no method 'save'
It occurs on line 54 of my app.js. I am unable to save a new Poll because it cannot find the function:
https://github.com/kelper/Poll/blob/master/app.js
Here is my models file, and the save function is on line 62:
https://github.com/kelper/Poll/blob/master/models.js
One other quick question. How can I exclude files from being committed? I keep committing swap files and such to my repo.
If you see anything else wrong with my code, please tell me. I know one person mentioned that my naming conventions are confusing. How should I be naming my variables?

PollModel is a function constructor, you want to create an object.
var PollModel = require('./models').PollModel; is wrong
var pollModel = new (require('./models').PollModel); is right.

Looks like you've got a proxy object built up using prototype. In this case you're going to have to 'new up' an instance to use it as Raynos mentioned.
I think what you're expecting is what an object literal provides, rather than a prototypical class. Something like:
module.exports.PollModel = {
findPolls : function (callback) { ... },
findById : function (id, callback) { ... },
updateById : function (id, body, callback) { ... }
}
I'd personally use the mongoose schema directly.
Mongoose uses the Schema object to do queries for that particular model, but if you actually want to create and save new objects of that schema type, you want to new up a new object.
// Assume you've exposed the mongoose Poll schema directly
var Poll = require('./models').Poll;
// Create a new instance
var instance = new Poll();
// Valid
instance.save();
// Not valid
instance.find(function(err, docs){});
// Valid
Poll.find(function(err, docs){});
// Not valid
Poll.save();

Related

how to use redis and sequelize together

im using redis for caching and sequelize as my orm.
i want to cache every query as key and it's result as value.
let me give you an example of how i'm trying to do it
imagine user request for all blogs that are created by himself, normally we would write something like this
blogs.findAll({where:{author:req.params.id}})
when i want to cache something like this i add an attribute named as model and for this example model would be equal to blog after that i will stringify this object and use it as key. this way i can easily create the key and check whether user response is cached or not, but i don't want to rewrite code for every request for checking redis and deciding to make query to database or not and i have 2 models now so i write this piece of code
for (m in models) {
models[m].myFindAll = function (options = {}) {
return new Promise(async function (resolve, reject) {
try {
const key = Object.assign({}, options);
key.model = m;
key.method = "findAll";
var result = await redis.get(JSON.stringify(key));
if (result) {
resolve(JSON.parse(result));
}
result = await models[m].findAll(options);
redis.set(JSON.stringify(key), JSON.stringify(result));
resolve(result);
} catch (err) {
reject(err);
}
});
};
}
as you can see i have an object that contains every model that i have and it is named models.
firstly i added User and after that i added Blog.
my problem is that when i try to use myFindAll function on User Model it won't work becuse it tries to set key.model with value of variable m which will be Blog in the run time, i solved it when i passed the model name an argument to my function but i don't want it that way and i think there should be a better way be i can't find it, isn't there some way of accessing right model through this object?
another thing that i tried to used libraries like sequelize-redis-cache and ... but i wanted to do it my way and i don't want to use this library

Getting around async issue in node.js application command line

My application is a simple mysql client used from command line - it connects to database and makes few queries to get information from database. Mysql functionality is encapsulated in a class and problem is since calls to mysql server is async (understandably) - the code flow reaches end of application.
And I am unable to refer to 'this'(Mysql) inside a method of Mysql class.
How do I get around this problem ?
Below is my code.
//CLASS
function Mysql(config) {
//...
}
//METHOD
Mysql.prototype.getDbInfo = function (cbk) {
this.showTables(function(e,r) {
// >>>>>>>>>> PROBLEM HERE using 'this' <<<<<<<<<<<
console.log(this.configVar);
});
}
module.exports = Mysql;
//CLASS OBJECT
var test = new Mysql(config);
//METHOD INVOKE
test.getDbInfo(function (err,results) {
//...
});
Every time that you jump into a callback function you are loosing the scope of the this object. There are different ways to work around it.
Assign this to another variable
The first solution is to assign the this object to another variable (e.g.: that, self). When you assign one variable to another and the first variable is an object then you keep the reference to the original object and you can use it within the callback. Something like that:
Mysql.prototype.getDbInfo = function (cbk) {
var self = this;
self.showTables(function(e,r) {
// >>>>>>>>>> PROBLEM HERE using 'this' <<<<<<<<<<<
console.log(self.configVar);
});
}
Bind the this object to the function
You can bind the this object to the function and like that you set the this keyword set to the provided value (in your case the scope outside of showTables function). You can read the documentation of this and you will be able to understand more:
Mysql.prototype.getDbInfo = function (cbk) {
this.showTables(function(e,r) {
// >>>>>>>>>> PROBLEM HERE using 'this' <<<<<<<<<<<
console.log(self.configVar);
}.bind(this));
}
Use es6 arrow functions
It is more or less the same solution like the first one. If you use a transpiler you will find out that it is translated like the first solution:
Mysql.prototype.getDbInfo = function (cbk) {
self.showTables((e,r) => {
// >>>>>>>>>> PROBLEM HERE using 'this' <<<<<<<<<<<
console.log(this.configVar);
});
}

Mongoose cannot use simple methods from within self

I'm trying to use findAndUpdate from within the object class but it's not working.
Getting the following error
findByIdAndUpdate is not a function
The code
Inside
gameScheme.methods.makeNextRound = function() {
First thing, assign self (Before any lines)
var self = this;
Returning a Promise
return self.findByIdAndUpdate(
self._id,
{ $push: { "rounds": { storyTitle: story.name } } }
).exec();
Cannot know how to get self properly from Mongoose since this method is defined before
// we need to create a model using it
let Game = mongoose.model('Game', gameScheme);
// make this available to our users in our Node applications
module.exports = Game;
On a side note, just using update doesn't work. The rounds do not get concatenated.
Also I think it's very unwise to use game.rouds[0] = "some round" or pushing directly and saving due to nodes async nature. (document miss match)
According to the Mongoose documentation for Schemas you define .methods and .statics on the schema. However, MongoDB methods are called directly on the model.
gameScheme.methods.makeNextRound = function () {
return this.model("Game").findByIdAndUpdate(this._id,
};
Important: the actual interaction with the data happens with the Model that you obtain through mongoose.model or db.model. That's the object that you can instantiate or that you can call .find(), .findOne(), etc upon. Don't confuse schemas and actual models!

Why isn't my Q promise working?

I'm new to promises and Q, and I'm trying to convert a route that uses query in node-mysql. Here are excerpts from my code:
var Q = require('q');
// connection defined elsewhere
router.get('/', function(req, res) {
var query = Q.denodeify(connection.query);
var promise = query("-- query ommitted --", [req.user.id]);
promise.then(console.log, console.error);
});
I'm trying to convert this from an existing set up that doesn't use promises, so I know the connection is set up properly and the query is valid. Whenever I try to request this route, I get the same message in stderr:
[TypeError: Cannot read property 'connectionConfig' of undefined]
I don't know where it's coming from so I'm not sure how to find the full stacktrace. I also tried an alternate version of this code where I had my own function instead of console.log and console.error, but this function was never called and the same error appeared.
Updated answer:
You're probably losing the lexical scope to connection when you denodeify the query method.
Looking at the Q documentation it says this can be an issue:
If you are working with methods, instead of simple functions, you can easily run in to the usual problems where passing a method to another function—like Q.nfcall—"un-binds" the method from its owner.
To fix this try using Q.nbind instead:
var query = Q.nbind(connection.query, connection);
var promise = query("-- query ommitted --", [req.user.id]);
promise.then(console.log, console.error);
Original answer:
Looking at the node-mysql source, the only place connectionConfig is accessed is in Pool.js. So my guess would be that you've got an issue with how the pool is being configured.

How do I mock MongoDB objects to test my data models?

I'm using the following logic (MOQ) to attempt to mock out the MongoDB csharp driver objects:
var svr = new Mock<MongoServer>(new MongoServerSettings());
var db = new Mock<MongoDatabase>(svr.Object, new MongoDatabaseSettings("hf_test",
new MongoCredentials("hf_test", "hf_pass"), GuidRepresentation.Standard,
SafeMode.False, false));
When I call db.Object, MOQ attempts to create an instance of my mock MongoDatabase, but it fails with a null-reference exception.
Note: I'm thinking of making an IMongoCollection interface, and wrapping MongoCollection in an instance of it. Then, I can simply mock that out... But that seems like a whole lot of unnecessary work.
I ended up creating my own interfaces which were basically shallow wrappers on top of the Mongo objects. I can mock these interfaces out, and at least test that the proper indices and filters are in my DAL queries.
this is probably no longer actual (and API might have been changed to be a bit more mock friendly), but here is how it can be done (using Moq):
var message = string.Empty;
var server = new Mock<MongoServer>(new MongoServerSettings());
server.Setup(s => s.IsDatabaseNameValid(It.IsAny<string>(), out message)).Returns(true);
var database = new Mock<MongoDatabase>(server.Object, "test", new MongoDatabaseSettings()
{
GuidRepresentation = MongoDB.Bson.GuidRepresentation.Standard,
ReadEncoding = new UTF8Encoding(),
ReadPreference = new ReadPreference(),
WriteConcern = new WriteConcern(),
WriteEncoding = new UTF8Encoding()
});
var mockedDatabase = database.Object;
Main problem here is, that MongoDatabase object calls method from MongoServer inside it's constructor to check, if name of database complies with rules.
Another issue is, that MongoDatabaseSettings should be initialized with all the values (since MongoDatabase constructor tries to check these against defaults provided from server).
Biggest issue is, that this mocking code might fall apart when new release of c# driver is released :). So writing wrappers on top of Mongo might be actually best fit.
You could try: https://github.com/razonrus/mongo-infrastructure, which aims to be a small library for mocking mongo collection objects for testing purposes. Repository contains sample tests with mocking mongo objects.
Setup mock object in test:
var mongoInitializer = new MockMongoWrapper<IMongoInitializer>()
.SetupDatabase(x => x.SampleDb, x => x
.SetupCollection<User>()
.SetupCollection<Article>(
m => m.Setup(c => c.FindOneById("")).Returns(CreateArticle())))
.SetupDatabase(x => x.LogDb,
x => x.SetupCollection<Log>())
.Object;

Resources