Mongoose .save is not a function - node.js

JS:
var express = require('express');
var router = express.Router();
// Mongoose
var mongoose = require('mongoose');
var mongoosedb = 'DBURL';
mongoose.connect(mongoosedb);
var database = mongoose.connection;
database.on('error', console.error.bind(console, 'connection error:'));
database.once('open', function() {
console.log('Mongoose is connected.');
});
var taskSchema = mongoose.Schema({
name: String,
isDone: Boolean
});
var Tasks = mongoose.model('Tasks', taskSchema);
// Get all tasks
router.get('/tasks', function(req, res, next) {
Tasks.find(function(err, tasks) {
if(err) {
console.log('error');
res.send(err);
}
res.json(tasks);
});
});
// Get single task
router.get('/task/:id', function(req, res, next) {
Tasks.findOne({_id: mongojs.ObjectId(req.params.id)}, function(err, task) {
if(err) {
res.send(err);
}
res.json(task);
});
});
// Save task
router.post('/task', function(req, res, next) {
var task = req.body;
if(!task.title || !(task.isDone + '')) {
res.status(400);
res.json({
"error": "Bad Data"
});
} else {
task.save(function(err, task) {
if(err) {
res.send(err);
}
res.json(task);
})
}
});
// Delete task
router.delete('/task/:id', function(req, res, next) {
Tasks.remove({_id: mongojs.ObjectId(req.params.id)}, function(err, task) {
if(err) {
res.send(err);
}
res.json(task);
});
});
// Update task
router.put('/task/:id', function(req, res, next) {
var task = req.body;
var updTask = {};
if (task.isDone) {
updTask.isDone = task.isDone;
}
if (task.title) {
updTask.title = task.title;
}
if (!updTask) {
res.status(400);
res.json({
"error": "Bad Data"
});
} else {
task.update({_id: mongojs.ObjectId(req.params.id)}, updTask, {}, function(err, task) {
if(err) {
res.send(err);
}
res.json(task);
});
}
});
module.exports = router;
I'm simply just trying to add a record to MongoDB using Mongoose.
After some Googling I couldn't find answer. My .find and .findOne methods work fine but for some reason I get the error task.save is not a function. What am I doing wrong?

I think your task creation is being done incorrectly.
First go ahead and import your model up at the top with your dependencies so we can access the model methods directly:
var express = require('express');
var router = express.Router();
// Mongoose
var mongoose = require('mongoose');
var mongoosedb = 'DBURL';
var Task = require('mongoose').model('Task'); // add your Task model
Then, in your save a task code, change it to this:
// Save task
router.post('/task', function(req, res, next) {
var task = new Task(req.body) // See http://mongoosejs.com homepage demo example for basic creation
if(!task.title || !(task.isDone + '')) {
res.status(400);
res.json({
"error": "Bad Data"
});
} else {
task.save(function(err, task) {
if(err) {
res.send(err);
}
res.json(task);
})
}
});
As your current Task creation is setup, you're just setting it to the req.body contents but not actually initializing an instance via the mongoose methods.
I personally like to use mongoose promises instead, just because I tend to like the style more. But you could also do something like this, if you have given access to your Task model via grabbing it as a dependency (as shown above):
Task.create(req.body)
.then(function(newTask) {
console.log("Task created successfully.");
return res.json(newTask); // using res.json here
})
.catch(function(err) {
console.log("There was a problem creating task.");
return res.status(500).json(err); // sends status with json obj
})
Anyhow, I hope this helps, let me know if this works, if not I'll check back later and see!

Your variable task is the body object you have defined previously :
var task = req.body;
If you want to generate a Tasks document from it, use :
var newTask = new Tasks(task);
newTask.save(function(err, task) {
if (err) {
res.send(err);
}
res.json(task);
});
Check mongoose Models documentation
You have also confused task.update with Tasks.update

Related

Cannot get / Error in MEAN stack application

I'm following the tutorial of Heroku: https://devcenter.heroku.com/articles/mean-apps-restful-api
I followed every step without the deployment to Heroku server and worked in my localhost.
So when I open my application with the port localhost/8080 I found the error of (Cannot Get / ).
this is my server code :
var express = require("express");
var bodyParser = require("body-parser");
var mongodb = require("mongodb");
var ObjectID = mongodb.ObjectID;
var CONTACTS_COLLECTION = "contacts";
var app = express();
app.use(bodyParser.json());
// Create link to Angular build directory
var distDir = __dirname + "/dist/";
app.use(express.static(distDir));
// Create a database variable outside of the database connection callback to reuse the connection pool in your app.
var db;
// Connect to the database before starting the application server.
mongodb.MongoClient.connect(process.env.MONGODB_URI || "mongodb://localhost:27017/test", { useNewUrlParser: true }, function (err, client) {
if (err) {
console.log(err);
process.exit(1);
}
// Save database object from the callback for reuse.
db = client.db();
console.log("Database connection ready");
// Initialize the app.
var server = app.listen(process.env.PORT || 8080, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
});
// CONTACTS API ROUTES BELOW
// Generic error handler used by all endpoints.
function handleError(res, reason, message, code) {
console.log("ERROR: " + reason);
res.status(code || 500).json({"error": message});
}
/* "/api/contacts"
* GET: finds all contacts
* POST: creates a new contact
*/
app.get("/api/contacts", function(req, res) {
db.collection(CONTACTS_COLLECTION).find({}).toArray(function(err, docs) {
if (err) {
handleError(res, err.message, "Failed to get contacts.");
} else {
res.status(200).json(docs);
}
});
});
app.post("/api/contacts", function(req, res) {
var newContact = req.body;
newContact.createDate = new Date();
if (!req.body.name) {
handleError(res, "Invalid user input", "Must provide a name.", 400);
} else {
db.collection(CONTACTS_COLLECTION).insertOne(newContact, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to create new contact.");
} else {
res.status(201).json(doc.ops[0]);
}
});
}
});
/* "/api/contacts/:id"
* GET: find contact by id
* PUT: update contact by id
* DELETE: deletes contact by id
*/
app.get("/api/contacts/:id", function(req, res) {
db.collection(CONTACTS_COLLECTION).findOne({ _id: new ObjectID(req.params.id) }, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to get contact");
} else {
res.status(200).json(doc);
}
});
});
app.put("/api/contacts/:id", function(req, res) {
var updateDoc = req.body;
delete updateDoc._id;
db.collection(CONTACTS_COLLECTION).updateOne({_id: new ObjectID(req.params.id)}, updateDoc, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to update contact");
} else {
updateDoc._id = req.params.id;
res.status(200).json(updateDoc);
}
});
});
app.delete("/api/contacts/:id", function(req, res) {
db.collection(CONTACTS_COLLECTION).deleteOne({_id: new ObjectID(req.params.id)}, function(err, result) {
if (err) {
handleError(res, err.message, "Failed to delete contact");
} else {
res.status(200).json(req.params.id);
}
});
});
PS: when I run the command ng serve: the main page shows but no connection with the database it's just a static page .. please help
and I'm a beginner in this mean languages.
It seems that it misses a part in your server code.
You have configured your API part, which can be called by your Angular app, but you're not serving your Angular app.
You should listen to all GET request and send as only file your index.html which in fact should contain your Angular SPA.
Something like this:
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'));
});
You can have a look at the Express doc: http://expressjs.com/fr/api.html#res.sendFile

Express response is not defined when using separate callback

Just an elementary question.
The following code return tasks successfully:
const mongojs = require('mongojs');
const db = mongojs('localhost:27017/tasks', ['tasks']);
router.get('/tasks', function(req, res, next) {
db.tasks.find(function(err, tasks) {
if (err) {
res.send(err);
}
if (tasks) {
res.json(tasks);
}
});
});
But, when I split it and call it as callback, it returns: References: tasks is not defined.
Repository.js:
const mongojs = require('mongojs');
const db = mongojs('localhost:27017/tasks', ['tasks']);
module.exports = {
ReadAllTasks(callback) {
db.tasks.find(function(err, tasks) {
if (err) {
callback(err, null);
}
callback(null, tasks);
});
}
}
Route.js:
const express = require('express');
const router = express.Router();
const repository = require('./repository');
router.get('/tasks', function(req, res, next) {
repository.ReadAllTasks(function(err, tasks) {
if (err) {
res.send(err);
}
if (tasks) {
res.json(tasks);
}
})
});
module.exports = router;
Anyone know to fix it?
try this, because you are not returning the valid object.
module.exports = {
ReadAllTasks: (callback)=>{
db.tasks.find(function(err, tasks) {
if (err) {
callback(err, null);
}
callback(null, tasks);
});
}
}

What is the simplest and/or best way to send data between routes in node.js express?

My setup is like this:
I get data from omDB using a omdb lib from github, this whole parts looks like this:
router.post('/search', function(req, res) {
var omdb = require('omdb');
var title = req.body.title;
omdb.get( {title: title}, true, function(err, movie){
if(err) {
return console.log(err);
}
if(!movie) {
return console.log('No movie found');
}
//console.log('%s (%d)', movie.title, movie.year);
result = movie.title+movie.year+movie.poster;
console.log(result);
res.redirect('/result');
})
});
And then i want to use the result from that post request in another route:
router.get('/result', function(req, res) {
res.render('result', { title: title});
});
What is the best and hopefully simplest approach to do this, consider that I am a node.js noob.. :)
Assuming you're using express.js, you could use the session middleware:
router.post('/search', function(req, res) {
var omdb = require('omdb');
var title = req.body.title;
omdb.get( {title: title}, true, function(err, movie){
if(err) {
return console.log(err);
}
if(!movie) {
return console.log('No movie found');
}
//console.log('%s (%d)', movie.title, movie.year);
req.session.result = {
title: movie.title,
year: movie.year,
poster: movie.poster
};
res.redirect('/result');
})
});
then:
router.get('/result', function(req, res) {
if (req.session.result) {
var result = req.session.result;
req.session.result = null;
res.render('result', { movie: result });
}
else {
// Redirect to error page.
}
});

PUT and DELETE always route to GET in Node + Express

I'm a beginner in Node/Express. I tried to make an CRUD application but stuck at update and delete. I think my router code is problematic but I don't know why. The following code is in my controller, everything works but PUT and DELETE. It always route to GET. I tried to use next(); but it returns this error: Can't set headers after they are sent..
I can make the delete works by using GET /:company_id/delete but it's not a good and standardized solution. How can I get update and delete process worked?
'use strict';
var Companies = require('../../models/companies');
module.exports = function (router) {
// INDEX
// accessed at GET http://localhost:8000/companies
router.get('/', function (req, res) {
Companies.find(function(err, model) {
if (err) {
res.send(err);
}
else {
res.format({
json: function () {
res.json(model);
},
html: function () {
res.render('companies/index', model);
}
});
}
});
});
// CREATE VIEW
// accessed at GET http://localhost:8000/companies/create
router.get('/create', function (req, res) {
res.render('companies/create');
});
// CREATE DATA
// accessed at POST http://localhost:8000/companies
router.post('/', function (req, res) {
var name = req.body.name && req.body.name.trim();
var type = req.body.type && req.body.type.trim();
// VALIDATION
if (name === '') {
res.redirect('/companies/create');
return;
}
var model = new Companies({name: name, type: type});
model.save(function(err) {
if (err) {
res.send(err);
}
else {
res.redirect('/companies');
}
});
});
// READ
// accessed at GET http://localhost:8000/companies/:company_id
router.get('/:company_id', function(req, res) {
Companies.findById(req.params.company_id, function(err, model) {
if (err) {
res.send(err);
}
else {
res.render('companies/read', model);
}
});
});
// UPDATE VIEW
// accessed at GET http://localhost:8000/companies/:company_id/edit
router.get('/:company_id/edit', function(req, res) {
Companies.findById(req.params.company_id, function(err, model) {
if (err) {
res.send(err);
}
else {
res.render('companies/edit', model);
}
});
});
// UPDATE DATA
// accessed at PUT http://localhost:8000/companies/:company_id
router.put('/:company_id', function(req, res) {
Companies.findById(req.params.company_id, function(err, model) {
if (err) {
res.send(err);
}
else {
model.name = req.body.name;
model.type = req.body.type;
model.save(function(err) {
if (err) {
res.send(err);
}
else {
res.redirect('/companies');
}
});
}
});
});
// DELETE
// accessed at DELETE http://localhost:8000/companies/:company_id
router.delete('/:company_id', function (req, res) {
Companies.remove({ _id: req.params.company_id }, function(err) {
if (err) {
res.send(err);
}
else {
res.redirect('/companies');
}
});
});
};
HTML forms only support GET and POST. XMLHTTPRequest supports PUT and DELETE however, so you may have to go that route OR use something like method-override to allow HTML forms to submit using other HTTP verbs.

How do I pass multiple models into a view?

I am easily and successfully passing a single model into a view in one of my express routes like this:
exports.locations = function(req, res){
Location.find(function(err, results) {
res.render('locations', { title: 'Locations', locations: results });
});
};
I have another route where I need to pass 2 result sets into the view, how do I do that? I have tried doing this, but it doesn't seem to be working:
exports.locationdetail = function(req, res) {
var packages = Package.find();
Location.findById(req.params.id, function(err, result) {
res.render('location-detail', { title: 'Location Details', location: result, packages: packages });
});
};
Edit 1
The error I am getting is:
Cannot read property 'name' of undefined
My model looks like this:
var mongoose = require('mongoose')
,Schema = mongoose.Schema;
var PackageSchema = new mongoose.Schema({
name: String,
prev_package: String,
featured: Boolean,
services: Array
});
module.exports = mongoose.model('Package', PackageSchema);
And I am using this model in another view, and everything is working like a champ.
var mongoOp = require("./models/mongo");
var async = require('async');
router.get("/",function(req,res){
var locals = {};
var userId = req.params.userId;
async.parallel([
//Load user data using Mangoose Model
function(callback) {
mongoOp.User.find({},function(err,user){
if (err) return callback(err);
locals.user = user;
callback();
});
},
//Load posts data using Mangoose Model
function(callback) {
mongoOp.Post.find({},function(err,posts){
if (err) return callback(err);
locals.posts = posts;
callback();
});
}
], function(err) { //This function gets called after the two tasks have called their "task callbacks"
if (err) return next(err); //If an error occurred, we let express handle it by calling the `next` function
//Here `locals` will be an object with `user` and `posts` keys
//Example: `locals = {user: ..., posts: [...]}`
res.render('index.ejs', {quotes: locals.user,userdata: locals.posts})
});
});
So, it looks like this was another asynchronous "gotcha". Putting this into a nested callback did the trick:
exports.locationdetail = function(req, res) {
Location.findById(req.params.id, function(err, result) {
Package.find(function (err, results) {
res.render('location-detail', { title: 'Location Details', location: result, packages: results });
});
});
};

Resources