node express with orm2 & separated model files - javascript

I am using node & express (framework for node).
I wan't to use the node-orm2 framework for node for communicating with my MySQL database. To keep a nice structure I want to split up my models in separated files. I've been using the documentation on github but somehow I can't make it work.
app.js:
app.use(orm.express("mysql://********:********#localhost/*********",
{
define: function(db, models){
db.load('./models', function(err){
models.movie = db.models.Movie;
});
}
}));
models.js:
module.exports = function (db, fn) {
db.load("movie", function (err) {
if (err) {
return fn(err);
}
});
//etc
return fn();
};
movie.js:
module.exports = function (db, fn) {
db.define('movie', {
id : { type: "number" },
title : { type: "text" },
year : { type: "number" },
rating : { type: "number" },
description : { type: "text" }
}, {
methods : {
}
});
return fn();
};

Copied help from github issue tracker (from lastmove):
I am using the built in express middleware.
It works fine for me.
I have a folder Model.
With one file par model.
Example the user model:
user.js
module.exports = function(db, cb)
{
var User = db.define('user', {
userName : String,
password : String,
mail : String,
mark : Number,
lastAlertSent : Date,
subscriptionDate : Date,
lastAction : Date,
specialUser : Boolean,
uuid : String
},
{
validations:
{
userName : [orm.enforce.required(error.errorStr(error.missingRequiredField, "userName missing")), orm.enforce.unique({ ignoreCase: true }, error.errorStr(error.usernameAlreadyUsed, "userName already used")), orm.enforce.ranges.length(3, undefined, error.errorStr(error.usernameTooShort, "userName too shoty"))],
...
And in the Models folder i have an index.js
In this file i define the relations betweens my models, and I load my models.
File:
models/index.js
checkError = function(cb, err)
{
if (err)
return cb(err);
return cb();
}
module.exports = function(db, cb)
{
db.load("./user.js", function (err) {checkError(cb, err)});
db.load("./alert.js", function (err) {checkError(cb, err)});
db.load("./comment.js", function (err) {checkError(cb, err)});
db.load("./metropole.js", function (err) {checkError(cb, err)});
db.load("./period.js", function (err) {checkError(cb, err)});
db.load("./stop.js", function (err) {checkError(cb, err)});
db.load("./line.js", function (err) {checkError(cb, err)});
db.load("./types.js", function (err) {checkError(cb, err)});
db.load("./historique.js", function(err) {checkError(cb, err)});
var User = db.models.user;
var Alert = db.models.alert;
var Comment = db.models.comment;
var Metropole = db.models.metropole;
var Stop = db.models.stop;
var Line = db.models.line;
var Period = db.models.period;
var Types = db.models.types;
var Hist = db.models.historique;
Alert.hasOne("stop", Stop, {reverse : "alerts"});
Alert.hasOne("line", Line, {reverse : "alerts"});
and after all in my Express initialization i add this:
app.use(orm.express(opts, {
define: function (db, models, next) {
db.load("./models/models", function (err2)
{
if (err2)
throw err2;
db.sync();
})
next();
}

Related

Using Multiple FindOne in Mongodb

I am trying to extend the amount of fields that our API is returning. Right now the API is returning the student info by using find, as well as adding some information of the projects by getting the student info and using findOne to get the info about the project that the student is currently registered to.
I am trying to add some information about the course by using the same logic that I used to get the project information.
So I used the same findOne function that I was using for Projects and my logic is the following.
I created a variable where I can save the courseID and then I will put the contents of that variable in the temp object that sending in a json file.
If I comment out the what I added, the code works perfectly and it returns all the students that I require. However, when I make the additional findOne to get information about the course, it stops returning anything but "{}"
I am going to put a comment on the lines of code that I added, to make it easier to find.
Any sort of help will be highly appreciated!
User.find({
isEnrolled: true,
course: {
$ne: null
}
},
'email pantherID firstName lastName project course',
function(err, users) {
console.log("err, users", err, users);
if (err) {
return res.send(err);
} else if (users) {
var userPromises = [];
users.map(function(user) {
userPromises.push(new Promise(function(resolve, reject) {
///////// Added Code START///////
var courseID;
Course.findOne({
fullName: user.course
}, function(err, course) {
console.log("err, course", err, course);
if (err) {
reject('')
}
courseID = course ? course._id : null
//console.log(tempObj)
resolve(tempObj)
}),
///// ADDED CODE END //////
Project.findOne({
title: user.project
}, function(err, proj) {
console.log("err, proj", err, proj);
if (err) {
reject('')
}
//Course ID, Semester, Semester ID
//map to custom object for MJ
var tempObj = {
email: user.email,
id: user.pantherID,
firstName: user.firstName,
lastName: user.lastName,
middle: null,
valid: true,
projectTitle: user.project,
projectId: proj ? proj._id : null,
course: user.course,
courseId: courseID
}
//console.log(tempObj)
resolve(tempObj)
})
}))
})
//async wait and set
Promise.all(userPromises).then(function(results) {
res.json(results)
}).catch(function(err) {
res.send(err)
})
}
})
using promise could be bit tedious, try using async, this is how i would have done it.
// Make sure User, Course & Project models are required.
const async = require('async');
let getUsers = (cb) => {
Users.find({
isEnrolled: true,
course: {
$ne: null
}
}, 'email pantherID firstName lastName project course', (err, users) => {
if (!err) {
cb(null, users);
} else {
cb(err);
}
});
};
let findCourse = (users, cb) => {
async.each(users, (user, ecb) => {
Project.findOne({title: user.project})
.exec((err, project) => {
if (!err) {
users[users.indexOf(user)].projectId = project._id;
ecb();
} else {
ecb(err);
}
});
}, (err) => {
if (!err) {
cb(null, users);
} else {
cb(err);
}
});
};
let findProject = (users, cb) => {
async.each(users, (user, ecb) => {
Course.findOne({fullName: user.course})
.exec((err, course) => {
if (!err) {
users[users.indexOf(user)].courseId = course._id;
ecb();
} else {
ecb(err);
}
});
}, (err) => {
if (!err) {
cb(null, users);
} else {
cb(err);
}
});
};
// This part of the code belongs at the route scope
async.waterfall([
getUsers,
findCourse,
findProject
], (err, result) => {
if (!err) {
res.send(result);
} else {
return res.send(err);
}
});
Hope this gives better insight on how you could go about with multiple IO transactions on the same request.

Using async.js for deep populating sails.js

I have a big issue with my function in sails.js (v12). I'm trying to get all userDetail using async (v2.3) for deep populating my user info:
UserController.js:
userDetail: function (req, res) {
var currentUserID = authToken.getUserIDFromToken(req);
async.auto({
//Find the User
user: function (cb) {
User
.findOne({ id: req.params.id })
.populate('userFollowing')
.populate('userFollower')
.populate('trips', { sort: 'createdAt DESC' })
.exec(function (err, foundedUser) {
if (err) {
return res.negotiate(err);
}
if (!foundedUser) {
return res.badRequest();
}
// console.log('foundedUser :', foundedUser);
cb(null, foundedUser);
});
},
//Find me
me: function (cb) {
User
.findOne({ id: currentUserID })
.populate('myLikedTrips')
.populate('userFollowing')
.exec(function (err, user) {
var likedTripIDs = _.pluck(user.myLikedTrips, 'id');
var followingUserIDs = _.pluck(user.userFollowing, 'id');
cb(null, { likedTripIDs, followingUserIDs });
});
},
populatedTrip: ['user', function (results, cb) {
Trip.find({ id: _.pluck(results.user.trips, 'id') })
.populate('comments')
.populate('likes')
.exec(function (err, tripsResults) {
if (err) {
return res.negotiate(err);
}
if (!tripsResults) {
return res.badRequest();
}
cb(null, _.indexBy(tripsResults, 'id'));
});
}],
isLiked: ['populatedTrip', 'me', 'user', function (results, cb) {
var me = results.me;
async.map(results.user.trips, function (trip, callback) {
trip = results.populatedTrip[trip.id];
if (_.contains(me.likedTripIDs, trip.id)) {
trip.hasLiked = true;
} else {
trip.hasLiked = false;
}
callback(null, trip);
}, function (err, isLikedTrip) {
if (err) {
return res.negotiate(err);
}
cb(null, isLikedTrip);
});
}]
},
function finish(err, data) {
if (err) {
console.log('err = ', err);
return res.serverError(err);
}
var userFinal = data.user;
//userFinal.trips = data.isLiked;
userFinal.trips = "test";
return res.json(userFinal);
}
);
},
I tried almost everthing to get this fix but nothing is working...
I am able to get my array of trips(data.isLiked) but I couldn't get my userFInal trips.
I try to set string value on the userFinal.trips:
JSON response
{
"trips": [], // <-- my pb is here !!
"userFollower": [
{
"user": "5777fce1eeef472a1d69bafb",
"follower": "57e44a8997974abc646b29ca",
"id": "57efa5cf605b94666aca0f11"
}
],
"userFollowing": [
{
"user": "57e44a8997974abc646b29ca",
"follower": "5777fce1eeef472a1d69bafb",
"id": "5882099b9c0c9543706d74f6"
}
],
"email": "test2#test.com",
"userName": "dany",
"isPrivate": false,
"bio": "Hello",
"id": "5777fce1eeef472a1d69bafb"
}
Question
How should I do to get my array of trips (isLiked) paste to my user trips array?
Why my results is not what I'm expecting to have?
Thank you for your answers.
Use .toJSON() before overwriting any association in model.
Otherwise default toJSON implementation overrides any changes made to model associated data.
var userFinal = data.user.toJSON(); // Use of toJSON
userFinal.trips = data.isLiked;
return res.json(userFinal);
On another note, use JS .map or _.map in place of async.map as there is not asynchronous operation in inside function. Otherwise you may face RangeError: Maximum call stack size exceeded issue.
Also, it might be better to return any response from final callback only. (Remove res.negotiate, res.badRequest from async.auto's first argument). It allows to make response method terminal

synchronize and serialize function or tasks on node js

i am stacking on this problem since a week, it's a problem of synchronize on Node JS.
The process that I want to do is :
1- check the existence of table (collection). --> if not insertion of data
2- if the table was created, then i have to find all data on table and compare it with the data that i want to insert.
3- if the new data is already exist on the database (table) the program doesn't do any thing, if not the program inserts the new data to the the database (table).
So we have 3 functions should be scheduled.
function 1
var getCollection = function(collection, new_theme, nbr_indicateur,callback) {
dbObject.listCollections().toArray(function(err, collections){
if ( err ) throw err;
assert.equal(err, null);
collections.forEach(function(collect){
if(collect.name == collection)
{
callback(true);
}
else {
dbObject.collection(collection).insertOne( {
"name_theme" : new_theme,
"nbr_indicateur" : nbr_indicateur
}, function(err, result) {
assert.equal(err, null);
console.log("Inserted a document into the Table_Mapping_Theme collection.");
});
callback(false);
}
});
});
};
function 2 :
var getData = function(value, collection, theme, callback) {
var clb = true;
if(value)
{
dbObject.collection(collection).find({}).toArray(function(err, docs){
if ( err ) throw err;
assert.equal(err, null);
docs.forEach(function(doc){
if(doc.name_theme == theme)
{
console.log("ce theme existe déja");
clb = false;
}
});
});
}
callback(clb);
};
function 3 :
var insertData = function(value, collection, new_theme, nbr_indicateur, callback) {
if(value)
{
dbObject.collection(collection).insertOne( {
"name_theme" : new_theme,
"nbr_indicateur" : nbr_indicateur
}, function(err, result) {
assert.equal(err, null);
console.log("Inserted a document into the "+collection+" collection.");
});
}
callback("done");
};
calling those functions (app.post using express js)
here i tried with pyramid method but it doesn't work
app.post('/setting/add_theme', urlencodedParser, function(req, res) {
getCollection('Table_Theme', req.body.new_theme, req.body.nbr_indicateur, function(value0){ console.log("0"+value0);
getData(value0,'Table_Theme', req.body.new_theme, function(value1) { console.log("1"+value1);
insertData(value1, 'Table_Theme', req.body.new_theme, req.body.nbr_indicateur, function(value2){ console.log("2"+value2);
});
});
});
res.redirect('/setting');
});

how to execute MongoDB statements in strongloop's remote method

Hi My task is to create an remote method using strongloop & execute an mongoDB function for the rest API. my mongoDB is like
"db.users.count({user_email_id :"bhargavb#ideaentity.com",user_password:"5f4dcc3b5aa765d61d8327deb882cf99",isdeleted:1,user_status:1});
if (count=1) then"
to execute this in strongloop I'm trying something like
module.exports = function(GetUserFind) {
var server = require('../../server/server');
var db = server.dataSources.MongoTours;
db.connect(function(err, db) {
if (err) return console.log('error opening db, err = ', err);
console.log("db opened!");
GetUserFind.login = function(par,par2,par3,par4,cb){
console.log(par,par2,par3,par4);
db.collection('users', function(err, collection) {
console.log("the collection is"+ collection);
if (err) return console.log('error opening users collection, err = ', err);
collection.count ({user_email:par}, function(err, result) {
if(err) {
console.error(err);
return;
}
cb(null,result);
});
cb(null,par,par2,par3,par4);
});
}
});
GetUserFind.remoteMethod(
'login',
{
accepts: [{arg: 'user_email_id', type: 'string'},
{arg: 'user_password', type: 'string'},
{arg: 'isdeleted', type: 'number'},
{arg: 'user_status', type: 'number'}],
returns: {arg: 'result', type: 'object'},
http: {path:'/Loogin', verb: 'get'}
}
);
// db.close();
}
but I'm not able to do the same, can anyone tell me how can i execute mongoDB statements in strongloop remote methods
thanks in advance
I tried it the following way,
module.exports = function(GetUserFind) {
var response = 'User does not exists';
var server = require('../../server/server');
var sha256 = require('js-sha256');
// getUser function login declaration
GetUserFind.login = function(par, par2, cb) {
console.log(par, par2);
// calling users collection method
var MongoClient = require('mongodb').MongoClient;
var self = this;
this.callback = cb;
// to connect to mongoDB datasource
MongoClient.connect('mongodb://192.168.0.78:27017/tours', function(err,
db) {
console.log(sha256(par2));
if (err) {
// try{
console.log(err);
}
db.collection('users').find({
user_email_id : par,
user_password : sha256(par2)
},{user_password:0}).toArray(function(err, result) {
//https://docs.mongodb.org/manual/tutorial/project-fields-from-query-results/
if (err) {
throw err;
}
if (result.length > 0) {
self.callback(null, result);
// db.disconnect();
} else {
self.callback(null, response);
// db.disconnect();
}
});
});
}
GetUserFind.remoteMethod('login', {
// passing input parameters
accepts : [ {
arg : 'user_email_id',
type : 'string'
}, {
arg : 'user_password',
type : 'string'
} ],
// getting output parameters
// returns: {arg: 'user_email_id', type: 'string'},
returns : [ {
arg : 'result',
type : 'object'
} ],
http : {
path : '/Loogin',
verb : 'get'
}
});
// db.close();
};
This may help other.
If any one knows better & easy way, Please post or update the answer

Uploading files using Skipper with Sails.js v0.10 - how to retrieve new file name

I am upgrading to Sails.js version 0.10 and now need to use Skipper to manage my file uploads.
When I upload a file I generate a new name for it using a UUID, and save it in the public/files/ folder (this will change when I've got this all working but it's good for testing right now)
I save the original name, and the uploaded name + path into a Mongo database.
This was all quite straightforward under Sails v0.9.x but using Skipper I can't figure out how to read the new file name and path. (Obviously if I could read the name I could construct the path though so it's really only the name I need)
My Controller looks like this
var uuid = require('node-uuid'),
path = require('path'),
blobAdapter = require('skipper-disk');
module.exports = {
upload: function(req, res) {
var receiver = blobAdapter().receive({
dirname: sails.config.appPath + "/public/files/",
saveAs: function(file) {
var filename = file.filename,
newName = uuid.v4() + path.extname(filename);
return newName;
}
}),
results = [];
req.file('docs').upload(receiver, function (err, files) {
if (err) return res.serverError(err);
async.forEach(files, function(file, next) {
Document.create({
name: file.filename,
size: file.size,
localName: // ***** how do I get the `saveAs()` value from the uploaded file *****,
path: // *** and likewise how do i get the path ******
}).exec(function(err, savedFile){
if (err) {
next(err);
} else {
results.push({
id: savedFile.id,
url: '/files/' + savedFile.localName
});
next();
}
});
}, function(err){
if (err) {
sails.log.error('caught error', err);
return res.serverError({error: err});
} else {
return res.json({ files: results });
}
});
});
},
_config: {}
};
How do I do this?
I've worked this out now and thought I'd share my solution for the benefit of others struggling with similar issues.
The solution was to not use skipper-disk at all but to write my own custom receiver. I've created this as a Sails Service object.
So in file api/services/Uploader.js
// Uploader utilities and helper methods
// designed to be relatively generic.
var fs = require('fs'),
Writable = require('stream').Writable;
exports.documentReceiverStream = function(options) {
var defaults = {
dirname: '/dev/null',
saveAs: function(file){
return file.filename;
},
completed: function(file, done){
done();
}
};
// I don't have access to jQuery here so this is the simplest way I
// could think of to merge the options.
opts = defaults;
if (options.dirname) opts.dirname = options.dirname;
if (options.saveAs) opts.saveAs = options.saveAs;
if (options.completed) opts.completed = options.completed;
var documentReceiver = Writable({objectMode: true});
// This `_write` method is invoked each time a new file is received
// from the Readable stream (Upstream) which is pumping filestreams
// into this receiver. (filename === `file.filename`).
documentReceiver._write = function onFile(file, encoding, done) {
var newFilename = opts.saveAs(file),
fileSavePath = opts.dirname + newFilename,
outputs = fs.createWriteStream(fileSavePath, encoding);
file.pipe(outputs);
// Garbage-collect the bytes that were already written for this file.
// (called when a read or write error occurs)
function gc(err) {
sails.log.debug("Garbage collecting file '" + file.filename + "' located at '" + fileSavePath + "'");
fs.unlink(fileSavePath, function (gcErr) {
if (gcErr) {
return done([err].concat([gcErr]));
} else {
return done(err);
}
});
};
file.on('error', function (err) {
sails.log.error('READ error on file ' + file.filename, '::', err);
});
outputs.on('error', function failedToWriteFile (err) {
sails.log.error('failed to write file', file.filename, 'with encoding', encoding, ': done =', done);
gc(err);
});
outputs.on('finish', function successfullyWroteFile () {
sails.log.debug("file uploaded")
opts.completed({
name: file.filename,
size: file.size,
localName: newFilename,
path: fileSavePath
}, done);
});
};
return documentReceiver;
}
and then my controller just became (in api/controllers/DocumentController.js)
var uuid = require('node-uuid'),
path = require('path');
module.exports = {
upload: function(req, res) {
var results = [],
streamOptions = {
dirname: sails.config.appPath + "/public/files/",
saveAs: function(file) {
var filename = file.filename,
newName = uuid.v4() + path.extname(filename);
return newName;
},
completed: function(fileData, next) {
Document.create(fileData).exec(function(err, savedFile){
if (err) {
next(err);
} else {
results.push({
id: savedFile.id,
url: '/files/' + savedFile.localName
});
next();
}
});
}
};
req.file('docs').upload(Uploader.documentReceiverStream(streamOptions),
function (err, files) {
if (err) return res.serverError(err);
res.json({
message: files.length + ' file(s) uploaded successfully!',
files: results
});
}
);
},
_config: {}
};
I'm sure it can be improved further but this works perfectly for me.
The uploaded file object contains all data you need:
req.file('fileTest').upload({
// You can apply a file upload limit (in bytes)
maxBytes: maxUpload,
adapter: require('skipper-disk')
}, function whenDone(err, uploadedFiles) {
if (err) {
var error = { "status": 500, "error" : err };
res.status(500);
return res.json(error);
} else {
for (var u in uploadedFiles) {
//"fd" contains the actual file path (and name) of your file on disk
fileOnDisk = uploadedFiles[u].fd;
// I suggest you stringify the object to see what it contains and might be useful to you
console.log(JSON.stringify(uploadedFiles[u]));
}
}
});

Categories

Resources