Mongoose - Referencing another model using require - javascript

What I'm trying to do is to update one collection, Prize, and then based on the result from that update another collection, League.
I have the following code:
app.post('/auth/prize/:prizeId', function(req, res) {
console.log('POST /auth/prize/' + req.params.prizeId);
if (req.user) {
var mess = 'JOINED';
var query = {...};
var update = {...};
Prize.findOneAndUpdate(query, update, function(err, result) {
if (err || result === null) {
mess = 'ERROR Incorrect password';
res.send(mess);
return;
}
var League = require('./leagues_api');
var queryL = {...};
var updateL = {...};
League.findOneAndUpdate(queryL, updateL, function(e, r) {
if (e || r === null) {
mess = 'ERROR Incorrect password';
}
res.send(mess);
});
});
} else {
res.send(401, 'Not Admin!');
}
});
So, the issue is that I am seeing an error:
[TypeError: Object #<Object> has no method 'findOneAndUpdate']
I have two separate files to keep everything easy to manage, so I have this file, prizes_api.js, and another file, leages_api.js, which has defined it in the Schema and the Model for League:
var leagueSchema = new mongoose.Schema({...});
var League = mongoose.model('League', leagueSchema);
I use this same style elsewhere, but for some reason in this file I am seeing the error failure. Any advice on this please?
Thank you, Gary.

If calling require('./leagues_api') isn't returning the League model, then your module.exports isn't set up right in that file.
It should look like the following:
module.exports = League;

Related

Property cannot be read after wrapping function

var sync = Meteor.wrapAsync(connection.query);
var rows = sync(selectMailgunChecked);
var emails = rows.map(function(a) {
return a.email
});
var from = 'sample#email.com';
emails.forEach(function(entry) {
mailgunSend( entry, from, contentHTML, contentRAW, subject, tags);
});
Code above (wrapped function of connection.query from node-mysql use in Meteor app) gives me an arror:
Cannot read property 'typeCast' of undefined
It is somehow related to sync(selectMailgunChecked) and external library (from node-mysql) Connection.js:
Connection.prototype.query = function query(sql, values, cb) {
var query = Connection.createQuery(sql, values, cb);
query._connection = this;
if (!(typeof sql == 'object' && 'typeCast' in sql)) {
query.typeCast = this.config.typeCast;
}
if (query.sql) {
query.sql = this.format(query.sql, query.values);
}
this._implyConnect();
return this._protocol._enqueue(query);
};
Every variable in my code is defined and sucessfully passed. What Can be wrong here?
this.config in this line
query.typeCast = this.config.typeCast;
is undefined.
You have to define the context (this) in which the wrap async function connection.query is executed by passing it as the second parameter
var sync = Meteor.wrapAsync(connection.query, connection);

Async Recursion with JavaScript and Node.js

This is probably a noob JavaScript question, but I'm looking to know if my solution to a problem I am having is 'correct'
I have created the following sample application that recreates my error:
Firstly in index.js
var processor = require('./fileProcessor/processor.js');
var container = {
source: "source.txt",
destination: "destination.txt"
};
new processor().process(container);
I create my container object which has the name of the source file and the name of the destination file. This is passed into the process function of the processor:
var fileProcessor = require('./fileProcessor.js');
module.exports = function Processor() {
this.process = function(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, this.process);
} else {
file.write(container, this.process);
}
}
};
};
As you can see this calls the read and write functions passing in the container and the process function as the callback, the fileProcessor looks like this:
var fs = require('fs');
module.exports = function() {
this.read = function(container, callback) {
fs.readFile(container.source, function (err, data) {
if(err) throw err;
container.body = data;
callback(container);
});
};
this.write = function(container, callback) {
fs.writeFile(container.destination, container.body, function(err) {
if(err) {
return console.log(err);
}
container.finished = true;
callback(container);
});
};
};
In simple terms the processor calls file.read, which reads the file and calls back into the process function, which then calls the write function. However at the end of the write function an error is thrown:
callback(container);
^
TypeError: object is not a function
Obviously when passing in this.process to file.write(container, this.process); the this isn't the this I intend it to be!
If I update my processor by adding a processFunction variable:
var fileProcessor = require('./fileProcessor.js');
module.exports = function Processor() {
var processFunction = function(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, processFunction);
} else {
file.write(container, processFunction);
}
}
};
this.process = function(container) {
processFunction(container);
};
};
Everything works fine. Is this a good way to do this or is there a better solution?
I think this is a fine way to do it. There is one possible modification that you might make. Since you are creating a new name in your scope just for the purpose of recursing, you could just name your function and refer to it by its name inside of the function.
module.exports = function Processor() {
this.process = function processFunction(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, processFunction);
} else {
file.write(container, processFunction);
}
}
};
};
Then you can avoid creating a name (processFunction) that will be visible outside the function.
Take a look here for reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function#Named_function_expression

Express.js - foreach array of data and store them in the database

I'm using expressjs, bookshelf.js and I want to post array of data, foreach such data and save it.
I'm not exactly sure where the issue is (express, bookshelf or just plain old javascript), but here's the scenario: when I post the said array and try to iterate through it, I get the correct amount of saves into the database, but all have the value of the last item in array.
Here's the code:
router.post('/save/', function(req, res){
var data = req.body;
var result = [];
for (var i in data) {
var d = data[i];
if (d.user_id == -1) d.user_id = null;
new Term().where({'date_of_driving': d.day})
.fetch()
.then(function(terms){
if (terms != null) {
return new Term({'id':terms.id}).save(d).then(function(item_updated){});
} else {
return new Term().save(d).then(function(item_saved){});
}
})
.catch(function(error){
console.log(error);
});
}
res.send({'saved': 'ok'});
});
My understanding is, that these calls are asynchronous and always operate on the last data, because for sentence is quicker than save. Am I onto something?
What are some of the best, easiest and most correct solutions to this problem?
It's not clear from your code whether you want to the queries to be run in parallel or sequentially.
I am assuming parallel, but you can replace .map with .each and it will run sequentially
router.post('/save/', function(req, res){
Promise.map(req.body, function(d) {
if (d.user_id == -1) d.user_id = null;
return new Term().where({'date_of_driving': d.day}).fetch().then(function(terms){
if (terms != null) {
return new Term({'id':terms.id}).save(d);
} else {
return new Term().save(d);
}
});
}).then(function() {
res.send({'saved': 'ok'});
}).catch(Promise.OperationalError, function(e) {
// Note that stack reveals internal server code so you might
// not want to send it over in production
res.status(400).send({stack: e.stack, message: e.message});
});
});
There is no need to catch an error only to log it so I removed it. Only catch an error when you can handle it.
Essentially, the 'then' function will be executed asynchronously, and the loop will continue its execution independently, as you suspected.
I believe one solution is to define a function that will essentially take the parameter d as a reference and execute the asynchronous stuff with that. So this should work:
router.post('/save/', function(req, res){
var data = req.body;
var result = [];
for (var i in data) {
var d = data[i];
if (d.user_id == -1) d.user_id = null;
doTheThing(d);
}
res.send({'saved': 'ok'});
});
function doTheThing(d) {
new Term().where({'date_of_driving': d.day})
.fetch()
.then(function(terms){
if (terms != null) {
return new Term({'id':terms.id}).save(d).then(function(item_updated){});
} else {
return new Term().save(d).then(function(item_saved){});
}
})
.catch(function(error){
console.log(error);
});
}

Node/Express - How to wait until For Loop is over to respond with JSON

I have a function in my express app that makes multiple queries within a For Loop and I need to design a callback that responds with JSON when the loop is finished. But, I'm not sure how to do this in Node yet. Here is what I have so far, but it's not yet working...
exports.contacts_create = function(req, res) {
var contacts = req.body;
(function(res, contacts) {
for (var property in contacts) { // for each contact, save to db
if( !isNaN(property) ) {
contact = contacts[property];
var newContact = new Contact(contact);
newContact.user = req.user.id
newContact.save(function(err) {
if (err) { console.log(err) };
}); // .save
}; // if !isNAN
}; // for
self.response();
})(); // function
}; // contacts_create
exports.response = function(req, res, success) {
res.json('finished');
};
There are a few problems with your code besides just the callback structure.
var contacts = req.body;
(function(res, contacts) {
...
})(); // function
^ you are redefining contacts and res in the parameter list, but not passing in any arguments, so inside your function res and contacts will be undefined.
Also, not sure where your self variable is coming from, but maybe you defined that elsewhere.
As to the callback structure, you're looking for something like this (assuming contacts is an Array):
exports.contacts_create = function(req, res) {
var contacts = req.body;
var iterator = function (i) {
if (i >= contacts.length) {
res.json('finished'); // or call self.response() or whatever
return;
}
contact = contacts[i];
var newContact = new Contact(contact);
newContact.user = req.user.id
newContact.save(function(err) {
if (err)
console.log(err); //if this is really a failure, you should call response here and return
iterator(i + 1); //re-call this function with the next index
});
};
iterator(0); //start the async "for" loop
};
However, you may want to consider performing your database saves in parallel. Something like this:
var savesPending = contacts.length;
var saveCallback = function (i, err) {
if (err)
console.log('Saving contact ' + i + ' failed.');
if (--savesPending === 0)
res.json('finished');
};
for (var i in contacts) {
...
newContact.save(saveCallback.bind(null, i));
}
This way you don't have to wait for each save to complete before starting the next round-trip to the database.
If you're unfamiliar with why I used saveCallback.bind(null, i), it's basically so the callback can know which contact failed in the event of an error. See Function.prototype.bind if you need a reference.

error while using async in node.js

I am trying write a restapi using express framework and node.js. I am facing an error which I am unable to find out the root cause. I am getting the following error while trying to execute the code :
TypeError: Cannot read property 'node_type' of undefined where 'node_type' is a value that comes from a function
var GdbProcess = require('../../dao/gdb/processnds')
var mongo = require('mongodb');
var async = require('async');
exports.executeService = function(req,res){
//Make the process object to query
var manualProcessQuery = new Object();
manualProcessQuery.index = req.params.processmap;
manualProcessQuery.key = "pid";
manualProcessQuery.value = req.params.pid;
manualProcessQuery.event = req.params.event;
var tempDataNodeToExecute = new Object();
//This function returns an object (dataNodeToExecute) to execute
GdbProcess.getParametersbyNode(manualProcessQuery,function(err,dataNodeToExecute){
if(err) res.send(err);
tempDataNodeToExecute = dataNodeToExecute;
var isSystem = false;
if (tempDataNodeToExecute.node_type =="system"){
isSystem = true;
}
var count = 0;
async.whilst(
function () { return isSystem },
function (callback) {
//execute the function
executeSystem(dataNodeToExecute,function(err,executionStatus){
if (err) callback(err);
count++;
if(executionStatus=="completed"){
manualProcessQuery.value = tempDataNodeToExecute.pid;
manualProcessQuery.event = "completed";
GdbProcess.getParametersbyNode(manualProcessQuery,function(err,dataNodeToExecute2){
if(err) callback(err);
tempDataNodeToExecute = dataNodeToExecute2;
if (tempDataNodeToExecute.node_type == "manual"){
isSystem = false;
}
});
callback();
}
});
},
function (err) {
if(err) res.send(err);
res.send("success");
}
);
});
}
var executeManual = function(prosNodeToExecute,callback){
//do something
callback (null);
}
var executeSystem = function(prosNodeToExecute,callback){
//do something
callback(null,"completed");
}
When I debug the code, i clearly see that node_type is available. Can someone help me to find the root problem here ?
remove the new object tempDataNodeToExecute and use dataNodeToExecute instead of it, and it is a good practice to check for null of an object before using its property so that the program does not crashes.

Categories