Get model from mongoose db - node.js

I'm currently looking into building a small REST based service to which I can POST some data into a mongoose db and GET the data back.
Here's my main.js file:
var http = require("http");
var DAO = require("./DAO");
var express = require("express");
var util = require('util');
var app = express();
app.use(express.bodyParser());
app.post('/postIsles',function(req,res){
DAO[req.method](req.body);
res.send("body" + req.body.name);
});
app.get('/getIsles',function(req,res){
var isleVar = DAO[req.method](req);
res.send(isleVar);
});
app.listen("3000");
console.log("\nApp available at http://127.0.0.1:3000\n");
And DAO.js:
var mongoose = require('mongoose');
//Connect to database
mongoose.connect( 'mongodb://127.0.0.1:27017/library_database' );
//Schemas
var Isle = new mongoose.Schema({
name: String,
description: String,
lastStocked: Date
});
//Models
var IsleModel = mongoose.model( 'Isle', Isle );
function POST(request) {
var name = request.name;
var description = request.description;
var lastStocked = request.lastStocked;
console.log("POST REQ +" + request);
var isle = new IsleModel({
name: name,
description: description,
lastStocked: lastStocked
});
isle.save( function( err ) {
if( !err ) {
return console.log( 'created' );
} else {
return console.log( err );
}
});
}
function GET(request) {
return IsleModel.find( function( err, islesT ) {
if( !err ) {
console.log("isles :"+islesT);
return islesT;
} else {
return console.log( err );
}
});
}
exports.POST = POST;
exports.GET = GET;
When I try to run the GET, I get the following error:
TypeError: Converting circular structure to JSON
at Object.stringify (native)
I'm a bit unsure how to overcome this.

Remember when using Node.js: any operation that involves IO will be asynchronous.
Model#find is an asynchronous method, so isleVar is not set to the result you're expecting. Your result will only be available inside of the anonymous function that you pass into IsleModel.find
To fix your GET method, you'll need to modify your code to take into account the asynchronicity of the DB request and only send the response once your app has had a chance to retrieve data.
Below, is an example of one possible solution to fix /getIsles:
In main.js, modify your get route to pass in res (so it can be handled asynchronously)
app.get('/getIsles',function(req,res){
return DAO[req.method](req, res);
});
In DAO.js, have response send the data inside of your callback to IsleModel.find
function GET(request, response) {
IsleModel.find( function( err, islesT ) {
if( !err ) {
console.log("isles :"+islesT);
response.send(islesT);
} else {
return console.log( err );
}
});
}

Related

Unable to get variable from module exports

I have a connector.js file which using which I want to export dbResult object.
(function(){
var Massive = require("massive");
var connectionString = "postgres://postgres:postgres#localhost/postgres";
var db = Massive.connectSync({connectionString : connectionString});
var dbResult ;
db.query("Select * from company", function (err, data) {
dbResult = data;
console.log(data);
});
})(module.exports);
Now in Another file I am trying to get the dbResult and display the data:
var express = require("express");
var app = express();
var connectorObject = require("./Connector.js");
var Massive = require("massive");
app.get("/api/Steves",function(req,res){
res.set("Content-Type","application/json");
res.send(connectorObject.dbResult);
});
app.listen(3000);
console.log("Server Started on port 3000...");
But when I start the URL , not able to see any response .
Am I missing anything here.
What you want to do, is return a function that can be evaluated later for the result:
var Massive = require("massive");
var connectionString = "postgres://postgres:postgres#localhost/postgres";
var db = Massive.connectSync({connectionString : connectionString});
module.exports.getCompanies = function(callback) {
db.query("Select * from company", callback);
}
Then you can access it from your other files as:
var connector = require('./Connector');
connector.getCompanies(function( err, data ) {
if ( err ) return console.error( err );
console.log( data );
});

how to iterate over a shapefile in node.js

I have the following node.js code which reads a shapefile based on code from (https://github.com/mbostock/shapefile)
var shp=require('shapefile');
var path="polygons.shp"
var encoding="utf8"
function readRecords(path, encoding) {
return function() {
var callback = this.callback;
shp.read(path, encoding, function(error, header, records) {
callback(error, records);
}); }; };
var rs = readRecords(path,encoding)
console.log(rs)
when I execute the above code I get : undefined
any idea of how do I iterate over such object?
You need to read the header before you move into reading the records. This bit of code logs the entire shapefile to the console:
var shapefile = require( 'shapefile' ),
reader = shapefile.reader( 'polygons' );
var logger = function( error, record ) {
console.log( record );
if( record !== shapefile.end ) reader.readRecord( logger );
}
reader.readHeader( logger );

angularjs error on server callback

I'm making a call to the server using resource and when I go to the base URL of
/viewEvent
It works fine. I receive all the database entries. However, when I go to
/viewEvent/1234
where 1234 is the eventID
I get a undefined is not a function and this is a crash from within angular. Stack trace is
TypeError: undefined is not a function
at copy (http://localhost:8000/js/lib/angular/angular.js:593:21)
at http://localhost:8000/js/lib/angular/angular-resource.js:410:19
at wrappedCallback (http://localhost:8000/js/lib/angular/angular.js:6846:59)
at http://localhost:8000/js/lib/angular/angular.js:6883:26
at Object.Scope.$eval (http://localhost:8000/js/lib/angular/angular.js:8057:28)
at Object.Scope.$digest (http://localhost:8000/js/lib/angular/angular.js:7922:25)
at Object.Scope.$apply (http://localhost:8000/js/lib/angular/angular.js:8143:24)
at done (http://localhost:8000/js/lib/angular/angular.js:9170:20)
at completeRequest (http://localhost:8000/js/lib/angular/angular.js:9333:7)
at XMLHttpRequest.xhr.onreadystatechange (http://localhost:8000/js/lib/angular/angular.js:9303:11) angular.js:575
When I examine the server, the request was made correctly. I can see that it got 1234 and it pulls the correct entry from the mongo database.
This is the controller logic
.controller("viewEventsController", ["$scope", 'EventService', '$location', function($scope, EventService, $location){
var path = $location.path().split('/');
var pathSize = path.length;
$scope.events = [];
if(pathSize === 2){
console.log("No event ID");
$scope.events = EventService.query();
}
else{
console.log("Event ID specified");
EventService.get({"eventID": path[pathSize - 1]}, function(data){
//$scope.events.push(data);
console.log(data);
}, function(error){
console.log(error);
});
}
}]);
and the service logic
service.factory('EventService', function($resource){
return $resource('api/viewEvent/:eventID');
});
It never makes it back to the controller so I'm "confident" it's not that. (watch it be that)
Not sure if the best way, but I got it working by doing
In service:
service.factory('EventService', function($resource){
return $resource('api/viewEvent/:eventID',
{eventID:"#eventID"},
{
'getSingleEvent': {
url: "api/viewEvent/:eventID",
method: "GET",
isArray: true
}
}
);
controller
var path = $location.path().split('/');
var pathSize = path.length;
EventService.getSingleEvent({"eventID":path[pathSize - 1]}, function(result){
$scope.updateEvent();
});
Server
routes = require('./routes')
var router = express.Router();
router.get('/api/viewEvent/:eventID', routes.viewEvent);
and in the routes directory I have a js file with
var mongoose = require('mongoose');
var db = mongoose.createConnection('localhost', 'eventApp');
var eventSchema = require('../models/createEvent.js').eventSchema;
var event = db.model('events', eventSchema);
exports.viewEvent = function(req, res){
console.log(req.params.eventID);
if(req.params.eventID) {
event.find({"_id": req.params.eventID}, function (error, events) {
console.log(events);
res.send(events);
});
}
else{
event.find({}, function (error, events) {
console.log(events);
res.send(events);
})
}
};

RESTful CRUD for Angular and Express $resource

I have my JSON querying and creating correctly. I'm a bit stuck on how to remove items from the server. They are being removed in angular but I can't seem to get the connection right for removing them on the server.
My server.js:
var hcController = require('./server/controllers/services-controller.js')
//REST API
app.get('/api/hc', hcController.list);
app.post('/api/hc', hcController.create);
app.delete('/api/hc:_id', hcController.delete);
My server-side model
var mongoose = require('mongoose');
module.exports = mongoose.model('HealingCenterData',{
title: String,
shortname: String,
summary: String,
description: String
});
My server-side controller
var Hc = require('../models/healingcenter-model.js')
module.exports.create = function (req, res) {
var hc = new Hc(req.body);
hc.save(function (err, result){
res.json(result);
});
}
module.exports.list = function (req,res) {
Hc.find({}, function (err, results){
res.json(results);
});
}
module.exports.delete = function (req, res) {
???????
});
}
My angular service:
app.factory("HC", ["$resource", function($resource) {
return {
API: $resource('/api/hc/:id')
}
}]);
My angular controller:
app.controller('servicesController', ['$scope', 'HC','$resource', function ($scope, HC, $resource) {
HC.API.query(function(results) {
$scope.services = results;
});
$scope.createService = function() {
var service = new HC.API();
service.title = $scope.serviceTitle;
service.shortname = $scope.serviceShortname;
service.summary = $scope.serviceSummary;
service.description = $scope.serviceDescription;
service.$save(function(result){
$scope.services.push(result);
$scope.serviceTitle = '';
$scope.serviceShortname = '';
$scope.serviceSummary = '';
$scope.serviceDescription = '';
});
}
$scope.removeItem = function(index){
$scope.services.splice(index, 1);
}
}]);
My JSON structure
{ "_id" : ObjectId("53bea9366a03a66c2dad68bb"), "title" : "Auto Clinic", "shortname" : "auto_clinic", "summary" : "Volunteers evaluate car problems and make minor repairs. Labor is free, and the car owner pays for any needed parts. Oil changes are performed at a reduced cost. All services are performed on Saturdays.", "description" : "No additional information yet.", "__v" : 0 }
On the server side try (I'm assuming you are using moongose) :
exports.delete = function(req,res){
if(req.params.id !==null || req.params.id!==undefined){
Hc.remove({_id:req.params.id},function(err){
res.send(200);
});
}
};
on the client side:
angular controller:
var endPoint = $resource('/api/hc/:id', {id:'#tId'});
$scope.removeItem = function(id){
var ep = new endPoint({tId:id});
ep.$delete(function(res){
//TODO: update local array in scope
});
};
EDIT:
you can just use the resource directly in the controller or just the service as you have done in your case, that's totally fine.

Q.js variables passing in parallel flows

While implementing promises got this code:
var MongoClient = require('mongodb').MongoClient
MongoClient.connect(db_uri, function(err, db) {
if(err) throw err;
var ccoll = db.collection('cdata');
app.locals.dbstore = db;
}
var json= {}
//Auth is a wrapped mongo collection
var Auth = app.locals.Auth;
var coll = app.locals.dbstore.collection('data');
var ucoll = app.locals.dbstore.collection('udata');
var ccoll = app.locals.dbstore.collection('cdata');
var Q = require('q');
//testing with certain _id in database
var _id = require('mongodb').ObjectID('530ede30ae797394160a6856');
//Auth.getUserById = collection.findOne()
var getUser = Q.nbind(Auth.getUserById, Auth);
//getUserInfo gives a detailed information about each user
var getUserInfo = Q.nbind(ucoll.findOne, ucoll);
var getUserData = Q.nbind(ccoll.findOne, ccoll);
//"upr" is a group of users
//getUsers gives me a list of users, belonging to this group
var getUsers = Q.nbind(ucoll.find, ucoll);
//Auth.getUserById = collection.find()
var listUsers = Q.nbind(Auth.listUsers, Auth);
var uupr = {}
var cupr = {}
getUserInfo({_id:_id})
.then(function(entry){
console.log('entry:', entry);
uupr = entry;
var queue = [getUsers({upr:entry.name}), getUserData({_id:entry._id})]
return Q.all(queue);
}
)
.then(function(array2){
console.log('array2:', array2);
cupr = array2[1]
var cursor = array2[0]
var cfill = Q.nbind(cursor.toArray, cursor);
return cfill();
}
)
.then(function(data){
json = {data:data, uupr:uupr, cupr:cupr}
console.log('json:', json)
res.render('test', {json : JSON.stringify(json)})
}
)
Its work can be described by a diagram:
getUserInfo()==>(entry)--+-->getUsers()=====>array2[0]--+-->populate user list===>data--->render
| |
+-->getUserData()==>array2[1]--+
I've used external variables uupr and cupr to store data from first .then calls.
So I have two problems:
1) Avoid using external variables.
2) rearrange code to get alternative flow diagram.
getUserInfo()==>(entry)--+-->getUsers()==>usersList-->populate user list==>usersData-+->render
| |
+-->getUserData()====>uprData-------------------------------+
Any advice is appreciated
Try something along the lines of this pseudo-code:
getUserInfo().then(function(userInfo) {
return Q.all([
userInfo,
getUsers(... userInfo ...).then(convert to array),
getUserData(... userInfo ...)
])
}).spread(function(userInfo, usersArray, userData) {
res.render(...)
}, function(err) {
handle the error
}).done()
You can simply nest them:
getUserInfo({_id:_id})
.then(function(entry){
console.log('entry:', entry);
return Q.all([
getUsers({upr:entry.name}),
getUserData({_id:entry._id})
]);
.spread(function(cursor, cupr) {
console.log('array2:', [cursor, cupr]);
return Q.ninvoke(cursor, "toArray")
.then(function(data){
return {data:data, uupr:entry, cupr:cupr};
});
});
}).then(function(json) {
console.log('json:', json)
res.render('test', {json: JSON.stringify(json)})
});
Now, to let the toArray not wait for the getUserData result, just do those in parallel:
getUserInfo({_id:_id})
.then(function(entry){
console.log('entry:', entry);
return Q.all([
getUsers({upr:entry.name}).invoke("toArray"),
getUserData({_id:entry._id})
]);
.spread(function(data, cupr) {
return {data:data, uupr:entry, cupr:cupr};
});
}).then(function(json) {
console.log('json:', json)
res.render('test', {json: JSON.stringify(json)})
});
(Using invoke instead an explicit then)

Resources