Loopback app.models.ModelName is undefined - node.js

Below code is accessing one model from another model, which returns undefined
var app = require('../../server/server');
module.exports = function(Regions) {
const Media = app.models.Media;
console.log( Media) // Returns Undefined
}
And I have tried below also, but same error
module.exports = function(Regions) {
console.log( Regions.app.models.Media) // Returns Undefined
}

Have you tried accessing your model like so:
require('loopback').getModel('Regions')

This is the way:
module.exports = function (Region) {
let app
Region.beforeRemote('find', function (ctx, unused, next) {
// Do something
next()
})
Region.on('attached', function (a) {
app = a
})
}
You can also create a boot script if you want to perform actions across models at boot time:

Is your sample code correctly located in common/models/regions.js?
Here is some other snippet for you:
'use strict';
var app = require('../../server/server');
var models = app.models;
var Media;
app.on('started', function () {
Media = models.Media;
});
module.exports = function (Regions) {
...
}

Related

node.js Xcontroller.init() is not a function

This is my index file:
(function (controllers){
var homeController = require("./homeController");
controllers.init = function (app) {
homeController.init(app);
};
}) (module.exports);
but when I am running my program, I am getting below error:
homeController.init is not a function
Most likely. You need to initialize Class before using it's methods.
So try like this
(function (controllers){
var homeController = require("./homeController");
var homeControllerClass = new homeController();
controllers.init = function (app) {
homeControllerClass.init(app);
};
}) (module.exports);
Hope this helps.

Re Initialization express Application

I have node.js application, which was built on express.js framework.
const app = express();
require('./config')(app);
require('./services')(app);
./config/config.js we instantiate config:
module.exports = function (app) {
const conf = {APIKey: 1234567890, url: '<someurl>'};
app.set('config', conf);
};
./services/APIService.js we create service instance(singleton)
module.exports = (app) => {
app.set('apiService', new APIService(app));
};
function APIService(app) {
const config = app.get('config');
this.key = config.APIKey;
};
APIService.prototype.sendRequest = () => {
const config = app.get('config');
this._send(config.url, 'some text');
};
Or, service2
module.exports = function(app) {
const config = app.get('config');
const myMod = require('myMod')(config.APIKey);
}
Cool, all works correct. But sometime administrator will change some config data. So, we create new config, set him to
newConf = {APIKey: 1234000000, url: '<some_new_url>'};
app.set('config', newConf);
APIService.sendRequest, will send request to CHANGED url, but APIService.key still unchanged. And myMod already instantiated with old config data.
We need write some setter methods, like this
//for APIService
APIService.prototype.setConfig = () => {
const config = app.get('config');
this.key = config.APIKey;
};
//for service 2
/* change const myMod to let myMod and create method for overriding */
or bang! kill and restart node.js server process. Bad idea. Maybe exist some method for this goal, something like app.restart() for safely reinitializing application(or, maybe, his parts)?
Did you try to call app.set('apiService', new APIService(app)); again ? or just have getter and setter on the prototype for your params.
Better way should be to have a new APIService object at each new request with a middleware, somehting like :
app.use(function (req, res, next){
req.api = new APIService(app);
next();
});
And use req.api.

REST data source in NodeJS/ Express MVC Pattern

What are the best practice to include external REST data sources in an Express MVC application?
Should we create a Model for the entities that we retrieve from external REST sources?
Let's take this practical example :
Our starting point is a user.js model that use mongoose for ODM.
var mongoose = require('mongoose');
var userModel = function () {
//Define a simple schema for our user.
var userSchema = mongoose.Schema({
name: String,
twitterId: Number
});
return mongoose.model('User', userSchema);
};
module.exports = new userModel();
Our objective is to show all tweets for a specific user, so we create a controller controller/userTweets.js where we prepare the data for our View.
How should we include the Twitter REST API in our application to handle this use case? (let's say we are using a nodejs client for twitter apis)
I'm more comfortable to use a specific model for the tweet entity, and then retrieve users tweet from the controller using our model, but how should our tweet.js model looks like?
Or should we design our REST API integration in a different way?
I would create a class called Tweet and a corresponding repository for it.
Assuming you are using es6, because why not.
lets call it tweets.js
'use strict';
module.exports = function (cfg) {
class Tweet {
constructor() {
this.userid = null;
this.text = null;
}
}
class Repo {
static getTweetsForUser(usedId) {
// make a call to twitter api, use https://www.npmjs.com/package/request
// psuedo code
let _ = require('lodash');
getTweets(userid, function (err, tweets) {
return new Promise(function (resolve, reject) {
if (err) {
return reject(err);
}
let data = [],
tweet = new Tweet;
if (! tweets.length) {
return resolve(data);
}
resolve(_.collect(tweets, function (t) {
tweet.userId = userId;
tweet.text = t.getTheTweet;
return tweet;
}));
});
});
}
}
return {
'tweet': Tweet,
'repo' : Repo
}
}
// export whatever modules, like above, lets call it index.js
'use strict';
let _ = require('lodash');
let modules = [
'tweets',
];
// cfg = any app configs that you might need in modules
function init(cfg) {
let core = {};
return _.collect(modules, function (m) {
core[m] = require('./' + m)(cfg);
});
}
module.exports = init;
Example - https://github.com/swarajgiri/express-bootstrap/blob/master/core/index.js
Now in routing side, in your main whatever is your server.js, inject the modules into an instance of express()
app.set('core', require('path/to/core/index')(whateverConfigYouMightNeed))
Once that is done, your route can look something like
'use strict'
let wrap = require('co-wrap');
route.get(':userId/tweets'), wrap(function* (req, res, next) {
let tweets = [];
try {
tweets = yield req.app.get('core').tweets.Repo.getTweetsForUser(req.params.userId)
} catch(e) {
// let the common error handler do its job.
return next(e);
}
// render whatever view you want.
});

How to properly use Mongoose models with Node.js?

I'm trying to use mongoose to control my db logic and transactions. I already got Schema definitions and I'm exporting the models.
Howver when i try to use a model, it will fail witl a message like:
return mongoose.model('Report', reportSchema);
} has no method 'find'...
This is my Model export:
module.exports = (function() {
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var reportSchema = mongoose.Schema({
category: ObjectId,
authorName: String,
authorEmail: String,
text: String,
address: String,
coordinates: {
type: "Point",
coordinates: [Number,Number]
},
date: {
type: Date,
default: new Date()
},
comments: Array
});
return mongoose.model('Report', reportSchema);
});
And this is how my controller functions are coded using mongoose inside:
module.exports = (function() {
var mongoose = require('mongoose');
var Report = require('../models/Report');
var Category = require('../models/Category');
function _getReports (request,response,next) {
var take = request.query.take;
var skip = request.query.skip;
Report.find({}).limit(take).skip(skip).exec(function (err,reports) {
callback(err,reports,response);
});
}
function _getReport (request,response,next) {
var id = request.params.id;
Report.findById({_id: id}, function (err,report) {
callback(err,report);
});
}
function _createReport (request,response) {
var newReport = new Report();
newReport.text = request.body.text;
newReport.category = request.body.category;
newReport.author = request.session.userId;
newReport.save(function (err,savedReport) {
callback(err,savedReport._id,response);
});
}
function _updateReport (request,response) {
var id = request.params.id;
var update = request.body.report;
Report.findByIdAndUpdate(id, update, function (err,foundReport) {
callback(err,foundReport,response);
});
}
function _deleteReport (request,response) {
var id = request.params.id;
Report.findByIdAndRemove(id, function (err,foundReport) {
callback(err,foundReport,response);
});
}
function _getReports (request,response,next) {
var take = request.query.take;
var skip = request.query.skip;
Report.find({}).limit(take).skip(skip).exec(function (err,reports){
callback(err,reports,response);
});
}
function _getCategories (request,response) {
var take = request.query.take;
var skip = request.query.skip;
Report.find({}).limit(take).skip(skip).exec(function (err,reports) {
callback(err,reports,response);
});
}
function _getCategoryReports (argument) {
var _id = mongoose.Types.ObjectId(request.params.id);
Report.find({category:id},{category:false},function (err, foundReports) {
callback(err,foundReports,response);
});
}
function _createCategory (request,response) {
var newCategory = new Category();
newCategory.name = request.body.name;
newCategory.save(function (err,savedCategory) {
callback(err,savedCategory._id,response);
});
}
function _updateCategory (request,response) {
var id = request.params.id;
var update = request.body.category;
Category.findByIdAndUpdate(id, update, function (err,foundCategory) {
callback(err,foundCategory,response);
});
}
function _deleteCategory (request,response) {
var id = request.params.id;
Category.findByIdAndRemove(id, function (err,foundCategory) {
callback(err,foundCategory,response);
});
}
function callback (err,object,response) {
if (err)
response.status(500).send(JSON.stringify(err));
response.send(JSON.stringify(object));
}
var apiController = {
getReports: _getReports,
getReport: _getReport,
createReport: _createReport,
updateReport: _updateReport,
deleteReport: _deleteReport,
getCategories: _getCategories,
getCategoryReports: _getCategoryReports,
createCategory: _createCategory,
updateCategory: _updateCategory
}
return apiController;
})();
Before this, a mongoose connection is ensured:
var connectToMongoose = function (mongoose,app) {
var connect = function () {
var options = { server: { socketOptions: { keepAlive: 1 } } };
mongoose.connect( 'mongodb://localhost/data4', options);
}
mongoose.connection.on('connected', function () {
console.log('Connected to db');
app.listen(32884, function() {
console.log("Listening at \"data4 port\" #:32884");
});
})
mongoose.connection.on('error', function (err) {
console.log(err);
});
mongoose.connection.on('disconnected', function () {
console.log('Disconnected from db, attempting to connect again...');
app.close();
connect();
});
connect();
};
module.exports = connectToMongoose;
Which is invoked by require('./db/mongoose-connect.js')(mongoose,app);
What am I doing wrong?
There are a couple issues here that I caught off the bat.
First off, I don't see a mongoose.connect() line that explicitly connects your mongoose ODM to a mongo server+database. An example would be:
var mongoose = require( 'mongoose' ),
Schema = mongo.Schema,
ObjectId = mongo.Schema.ObjectId;
mongoose.connect( 'mongodb://localhost/db_name' );
Your schema export looks fine. But you're using an anonymous function as your export. Since you're doing that, your require statement needs to change a little:
var Report = require('../models/Report')();
var Category = require('../models/Category')();
Notice the () at the end of the require statements. You need to execute the function that you're defining as your model file's module.export.
EDIT: I see that you added your mongoose connect code. At this point, executing the module.exports function that you assign in the model file should allow your mongoose models to function as intended.
When you export a function;
// file: A.js
module.exports = function () {
//some logic
};
And you want to use it on another file, when you require the A file, you are importing a function and in order to use that function, you need to to invoke it.
// file: B.js
var A = require('./A.js');
A();
so your model is exporting a function
module.exports = (function() {
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
// ..
// some code
// ..
return mongoose.model('Report', reportSchema);
});
and when you are importing your model from your controller, you need to execute your imported function so that your Report variable contains the model created:
module.exports = (function() {
var mongoose = require('mongoose');
var Report = require('../models/Report') ();
I have created a gist of how you could write your code using modules without using IIFE.
https://gist.github.com/wilsonbalderrama/d5484f3f530899f101dc
actually if you download all those files on a folder and run:
$ sudo npm install
$ mocha
You could see that all the tests created for the controller are passing.
In addition you don't need to use IIFE in Node.JS since when you are creating a module because you already have an isolated scope in Node.JS using modules.
// IIFE
module.exports = (function() {
var apiController = {
getReport: function () {}
}
return apiController;
})();
In Node.JS you can export a object,
// GOOD WAY
module.exports = {
getReport: function () {}
};

regarding foodme project in github

hello i have a question regarding the foodme express example over github:
code:
var express = require('express');
var fs = require('fs');
var open = require('open');
var RestaurantRecord = require('./model').Restaurant;
var MemoryStorage = require('./storage').Memory;
var API_URL = '/api/restaurant';
var API_URL_ID = API_URL + '/:id';
var API_URL_ORDER = '/api/order';
var removeMenuItems = function(restaurant) {
var clone = {};
Object.getOwnPropertyNames(restaurant).forEach(function(key) {
if (key !== 'menuItems') {
clone[key] = restaurant[key];
}
});
return clone;
};
exports.start = function(PORT, STATIC_DIR, DATA_FILE, TEST_DIR) {
var app = express();
var storage = new MemoryStorage();
// log requests
app.use(express.logger('dev'));
// serve static files for demo client
app.use(express.static(STATIC_DIR));
// parse body into req.body
app.use(express.bodyParser());
// API
app.get(API_URL, function(req, res, next) {
res.send(200, storage.getAll().map(removeMenuItems));
});
i don't understand where is the api folder. it doesn't exist and i don't understand how information is going in and out from there. i can't find it.
can someone please explain this to me?
another question:
there is a resource for the restaurant
foodMeApp.factory('Restaurant', function($resource) {
return $resource('/api/restaurant/:id', {id: '#id'});
});
and in the restaurant controller there is a query:
var allRestaurants = Restaurant.query(filterAndSortRestaurants);
and the following lines:
$scope.$watch('filter', filterAndSortRestaurants, true);
function filterAndSortRestaurants() {
$scope.restaurants = [];
// filter
angular.forEach(allRestaurants, function(item, key) {
if (filter.price && filter.price !== item.price) {
return;
}
if (filter.rating && filter.rating !== item.rating) {
return;
}
if (filter.cuisine.length && filter.cuisine.indexOf(item.cuisine) === -1) {
return;
}
$scope.restaurants.push(item);
});
// sort
$scope.restaurants.sort(function(a, b) {
if (a[filter.sortBy] > b[filter.sortBy]) {
return filter.sortAsc ? 1 : -1;
}
if (a[filter.sortBy] < b[filter.sortBy]) {
return filter.sortAsc ? -1 : 1;
}
return 0;
});
};
the things that isn't clear to me is:
how is that we are giving the query just a function without even activating it.
as i understand we should have passed the query somthing like:
{id: $routeParams.restaurantId}
but we only passed a reference to a function. that doesn't make any sense.
could someone elaborate on this?
thanks again.
var API_URL = '/api/restaurant';
var API_URL_ID = API_URL + '/:id';
var API_URL_ORDER = '/api/order';
These lines are just defining string constants that are plugged into Express further down. They're not a folder.
app.get(API_URL, function(req, res, next) {
res.send(200, storage.getAll().map(removeMenuItems));
});
So this function call to app.get(API_URL... is telling Express "Look out for GET requests that are pointed at the URL (your app's domain)/api/restaurant, and execute this function to handle such a request."
"api" is not a folder.
Every requests will pass through the app.get method.
This method will respond to the routes /api/restaurant as defined in the API_URL variable.

Resources