Mongoose findById Route Issue - node.js

I'm writing a web application primarily to serve as a shopping cart. The landing/homepage of the app reflects products that are currently available for sale. What I'd like to do is route to each product using the product ID. I've defined a product model (adminProductModel) as follows:
'use strict';
var mongoose = require('mongoose');
var productModel = function () {
//Define a super simple schema for our products.
var productSchema = mongoose.Schema({
name: String,
price: Number,
productImg: String,
description: String
});
return mongoose.model('Product', productSchema);
};
module.exports = new productModel();
I'm able to post, and get, and delete products using the above model via an admin controller. Works great! I've then gone ahead and created an items controller, model and template, which are defined as below, with the intention to route from the homepage(index.dust) to an item's page using the item/product's id.
The item controller:
'use strict';
var ItemModel = require('../../models/adminProductModel');
var db = require ('../../lib/database');
module.exports = function (router) {
router.get('/index/:id', function (req, res) {
db.ItemModel.findById({_id: req.params._id}, function (err, prod){
if(err){
console.log('FindById filter error:', err)
}
var model = {product: prod}
res.render('item/index', model);
});
});
};
The item model:
'use strict';
module.exports = function ItemModel() {
return {
name: 'item'
};
};
The relevant code on the homepage (index) is:
The template (using dust as rendering engine):
{>"layouts/master" /}
{<title}
Greatness!
{/title}
{<body}
{?products}
{#products}
<div class="col-sm-6 col-md-3">
<div class="thumbnail">
<img src="img/photo.png" alt="photo" width ="260" height = "180"/>
<center>
<h5>{.name}</h5>
<p>${.price}</p>
Buy
</center>
</div>
</div>
{/products}
{/products}
{/body}
When the anchor tag is clicked, it routes to correct ID, from the index page, but throws the following file not found error "URL /index/542237117b5f3e72136d70c5 did not resolve to a route".
What am I doing wrong here? I know I have to query the database for the products by its unique objectId. Am I implementing this wrong? If so, why does it resolve to a file not found error or at least render the correct markup?
Thanks a ton in advance. I've spend a few days thinking about this and I've exhausted all my approaches to solve this. I've included the database for completeness:
use strict';
var mongoose = require('mongoose');
var db = function () {
return {
config: function (conf) {
mongoose.connect('mongodb://' + conf.host + '/' + conf.database);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback() {
console.log('db connection open');
});
}
};
};
module.exports = db();
Would it perhaps be wise to define my itemModel with a separate schema? This seems redundant and more error prone. I'm going to read further into this and home for some feedback from here. Thanks again.

Hi your are getting id value from params but it is :id not :_id
you are doing like this
console.log("id value : "+req.params._id)
db.ItemModel.findById({_id: req.params._id}, function (err, prod){
it should be like this
console.log("id value : "+req.params.id)
db.ItemModel.findById({_id: req.params.id}, function (err, prod){

Related

CastError: Cast to ObjectId failed for value "favicon.ico" at path "_id" for model

I am learning how to make a node api with the help of a youtube tutorial but I get this error everytime when I run nodemon and go to the localhost. I haven't use nay favicon.ico in any part of my code. Can someone help me?
This is my full code for the movies model
var mongoose = require('mongoose');
//movie schema
var moviesSchema = mongoose.Schema({
Title: {
type: String,
required: true
},
Genre: {
type: String,
required: true
},
Release: {
type: String,
required: true
},
Director: {
type: String,
required: true
},
Stars: {
type: String,
required: true
},
Summary: {
type: String,
required: true
}
});
//export the schema
var Movies = module.exports = mongoose.model('Movies',moviesSchema);
//get movies
module.exports.getMovies = function(callback, limit){
Movies.find(callback).limit(limit);
};
//get movies by id
module.exports.getMovieById = function(id, callback){
Movies.findById(id, callback);
};
//add a movie
module.exports.addMovie = function(movie, callback){
Movies.create(movie, callback);
};
//update a movie
module.exports.updateMovie = function(id, movie, options, callback){
var query = {_id:id};
var update = {
Title : movie.Title,
Genre : movie.Genre,
Release : movie.Release,
Director : movie.Director,
Stars : movie.Stars,
Summary : movie.Summary
};
Movies.findOneAndUpdate(query, update, options, callback);
};
//delete a movie
module.exports.deleteMovie = function(id, callback){
var query = {_id:id};
Movies.remove(query, callback);
};
This is my index.js
var express = require('express');
var bodyParser = require("body-parser");
var mongoose = require('mongoose');
Movie = require('./models/movies');
var app = express();
app.use(bodyParser.json());
//mongoose connection
mongoose.connect('mongodb://localhost/movielist');
var db = mongoose.connection;
//get all movies json format
app.get('/',function(req,res){
Movie.getMovies(function(err,movies){
if(err){
throw err;
}
res.json(movies);
});
});
//get movie by id
app.get('/:_id',function(req,res){
Movie.getMovieById(req.params._id, function(err,movie){
if(err){
throw err;
}
res.json(movie);
});
});
//post new movies
app.post('/',function(req,res){
var movies = req.body;
Movie.addMovie(movies,function(err,movies){
if(err){
throw err;
}
res.json(movies);
});
});
//update new movies
app.put('/:_id',function(req,res){
var id = req.params._id;
var movies = req.body;
Movie.updateMovie(id, movies, {}, function(err,movies){
if(err){
throw err;
}
res.json(movies);
});
});
//delete an existing movie
app.delete('/:_id',function(req,res){
var id = req.params._id;
Movie.deleteMovie(id, function(err,movies){
if(err){
throw err;
}
res.json(movies);
});
});
app.listen(8000);
console.log("running on port 8000");
From what I can see in the console log is that the error might be from this code
//get movies by id
module.exports.getMovieById = function(id, callback){
Movies.findById(id, callback);
};
and in the index.js from this code
Movie.getMovieById(req.params._id, function(err,movie){
But I dont understand that favicon.ico failure
You need to add a <link> tag to your favicon icon image in the HTML or EJS file header which is at root ('/') and communicating with your server.
Adding the following generic tag will solve the problem:
<link rel="icon" type="image/svg+xml" href="https://example.com/image.svg">
Or if you have your own favicon (any image file, e.g. image.png shown below) file placed in the public folder, then you can use this:
<link rel="icon" href="image.png">
Explanation of the problem:
By default, your browser looks for an icon file each time you request a new page; some browsers cache this file after it's found the first time. The <link rel="icon" href="LOCATION"> points the browser to the location of the icon file which by convention is called Favicon.ico. If the href is an external URL, it will fetch the icon from that URL. If the href is a path (e.g. "Favicon.ico"), then it will look inside your public folder, and if it doesn't exist in the public folder then it will be called as a GET route on /Favicon.ico. This triggers your code to add that unwanted entry to the DB.
I just fought with this issue for quite some time, and tried a wide variety of fixes (including downgrading my version of Mongoose to 4.7.2 or lower, which was suggested elsewhere), but unfortunately none of them worked for me. That said, while I can't explain why this is happening*, there was one easy fix that worked for me:
Don't make requests to ~/:var . Instead add an additional layer in between, so that your request goes to ~/string/:var .
In your question, you have a get, a put, and a delete request for "/:". Alter those three lines of code, and any dependencies, and you should be more or less good to go.
*My best guess for why this is happening: something is failing to recognize the "/" path as empty, and instead is matching to both "/" and "/:X" simultaneously.
//get movie by id
app.get('/:_id',function(req,res){
Movie.getMovieById(req.params._id, function(err,movie){
if(err){
throw err;
}
res.json(movie);
});
A get request cant have params .
You should change it to a post request instead
I have a similar problem and it seems to be the browser fault. When you visit your localhost, it will send a request to http://localhost:PORT/favicon.ico which go to app.get('/:_id') and made _id="favicon.ico". So you should do this:
app.get('/:_id',function(req,res) {
// if req.params._id is favicon.ico then response immediately
if (req.params._id === "favicon.ico") {
return res.status(404)
}
// your code
Movie.getMovieById(req.params._id, function(err,movie){
if(err){
throw err;
}
res.json(movie);
});
I fixed it by adding the generic link tag to all my views (as mentioned above) and moving my static routes to the top and the dynamic routes to the bottom.
//views
<link rel="icon" type="image/svg+xml" href="https://example.com/image.svg">
//routes
app.get('/',...)
app.post('/',...)
app.get('/:id',...)
app.post('/:id',...)

Node.JS Express 4 - Mongoose Does not saving data

I am trying to save a data in MongoDB with Mongoose with Express.JS 4 and Bluebird.
What I have done is like this-
bin/www
var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
.......
.......
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function()
{// successfully connected!
console.log("Successfully Connected to Mongo-DB");
});
And getting this in console-
Successfully Connected to Mongo-DB` - So, MongoDB connected successfully
models/post.js
var mongoose = require('mongoose');
var postSchema = new mongoose.Schema({
created_by: String, //should be changed to ObjectId, ref "User"
created_at: {type: Date, default: Date.now},
text: String
});
module.exports = mongoose.model('Post', postSchema);
app.js
var Post_Data = require("./models/post");
....
....
router.get('/', function(req, res, next)
{
var Post = mongoose.model("Post");
var post = new Post({
created_by: ""+Math.random()
});
console.log( Post.create(post) );
res.render(
'index',
{
title : 'Express',
site_name : 'Our Site',
layout : 'templates/layout'
}
);
});
And after that I am getting this in console-
Promise {
_bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_promise0: undefined,
_receiver0: undefined }
But, nothing is saved, a proof for that is -
I am finding this-
After using MongoBooster.
Update-
My DB config is like this-
"MONGO_URI": "mongodb://localhost:27017/express_test",
"MONGO_OPTIONS": {
"db": { "safe": true },
"name":"express_test"
}
So, can anyone please help, why it is not saving anything?
Thanks in advance for helping.
The .create() function is a shortcut for new Model and .save(). You are trying to .create an instance of Model rather than a simple Object. See Constructing documents in Mongoose's Models documentation for their quick example.
The return from a Mongoose data function is just the promise of an asynchronous task to be run in the future, logging that is largely pointless. Use .then() to wait until the promise has been resolved.
Error handling is missing from your code as well, something could be getting thrown there. Use a .catch() for promise error handling.
Post.create({ created_by: ""+Math.random() })
.then(function (result) {
console.log('Saved' result)
})
.catch(function (err) {
console.error('Oh No', err)
})
All of this can be done with callbacks (like the Mongoose docco examples) but promises, particularly bluebird promises are nicer.
I just use this syntax combination to create and save my model:
var myPage = new LandingPage({
user:req.user,
slug: req.body.slug,
}).save(function(err,savedModel){
if(!err){
console.log(savedModel);
}
});
You are calling the wrong model in your app.js module as you are importing the model as
var Post_Data = require("./models/post"); // <-- Post_Data model never used
....
....
but creating a new Post model instance in your router implementation as
var Post = mongoose.model("Post"); // <-- different model
var post = new Post({
created_by: ""+Math.random()
});
You need to call and use the correct models. So I would suggest you re-write your app.js module to use the save() method as:
var Post = require("./models/post"); // <-- import correct Post model
....
....
router.get('/', function(req, res, next) {
var post = new Post({ created_by: ""+Math.random() });
post.save().then(function(post) {
console.log(post); // <-- newly created post
res.render('index', {
title: 'Express',
site_name: 'Our Site',
layout: 'templates/layout'
});
})
.catch(function(err) {
console.error('Oopsy', err);
});
});
if you store post schema in a variable by require then can use that variable.
var Post_Data = require("./models/post");
so can use new Post_Data no need to use var Post = mongoose.model("Post"); because you have already exported this schema module.exports = mongoose.model('Post', postSchema);
you can try this one :
var Post_Data = require("./models/post");
router.get('/', function(req, res, next)
{
var post = new Post_Data({created_by: ""+Math.random()});
post.save(function(error, data) {
if(error) {
return res.status(500).send({error: 'Error occurred during create post'});
}
return res.render('index',{
title : 'Express',
site_name : 'Our Site',
layout : 'templates/layout'
});
});
});
So it's true that if you're creating a document in memory by calling new Post(values) that you will save it with post.save(cb); rather than 'Post.create(post);, but I'm thinking that the underlying issue (though this isn't easy to be certain of based on the code you're showing) is that you're connecting with the MongoDB driver, rather than mongoose itself. Yourdb` variable isn't shown to be declared in the code you posted, so I'm making it an assumption.
That said, if I'm right, you need to call mongoose.connect or mongoose.createConnection in order for Mongoose to know it's connected to the db and save documents to it. You can pass an existing connection to mongoose, so if you're already doing so then I apologize for my erroneous assumption.

Remove an object by an id in mongodb and mongoose

I'm getting an error on robots.remove stating robots is not defined, But I can't possibly figure out exactly why. Please help. thank you.
mongoose.connect('mongodb://localhost/robots'); //connecting to localdb
router.delete('/:id', function(req,res){
var id = req.params.id;
console.log(id);
robots.remove({_id:ObjectId(id)}, function(err, result){ //undefined??
if (err) return res.status(500).send({err: 'Error: Could not delete robot'});
if(!result) return res.status(400).send({err: 'Robot bot deleted from firebase database'});
console.log('deleted!!!');
res.send(result);
});
});
You have to load the user model first.
var robots = require('../app/models/robots');//Load the model
robots.js file should look like this:
var mongoose = require('mongoose');
var robotSchema = mongoose.Schema({
//Your schema here
});
module.exports = mongoose.model('robots', robotSchema);

mongodb + mongoose: query not entering .find function

I am getting start with mongodb and mongoose but am having problems querying a database. There are a number of tutorials online for what I am trying to do but it just doesn't seem to work for me. My problem is that the .find() function is not even being called and the collection is not being displayed. I have a collection called Subjects in which I know there are some values (I manually entered them in the mongodb command line). I only tried including pertinent code but let me know if anything else is needed. Thanks in advance.
app.js file
require('./models/model.js');
var conn = mongoose.createConnection('mongodb://localhost/test');
var Subject = mongoose.model('Subjects');
Subject.find( { }, function (err, subjects) {
if(err) console.log("Error"); // There is no "Error"
console.log("Made it"); // There is no "Made it"
console.log(subjects);
});
model.js file
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var SubjectsSchema = new Schema ({
subject: { type: String }
});
module.exports = mongoose.model('Subjects', SubjectsSchema);
Call mongoose.connect instead of mongoose.createConnnection to open the default connection pool that will be used by models created using mongoose.model:
mongoose.connect('mongodb://localhost/test');

Mongoose save callback doesn't fire

I'm new to mongoose and I'm having a hard time finding the issue within my code. I'm building a REST server using Sails.js and Mongoose. I have a node module (e.g. "sails-mongoose") for exporting mongoose, where I also connect to my database:
var mongoose = require('mongoose');
mongoose.connect('mongodb://#localhost:27017/fooria');
module.exports = mongoose;
And in my model.js:
var adapter = require('sails-mongoose');
var schema = new adapter.Schema({
firstname: {
type: String,
required: true,
trim: true
}
});
module.exports = {
schema: schema,
model: adapter.model('Collection', schema)
}
In my controller's create method I have:
create: function(req, res, next) {
var userData = {firstname: 'Test'};
var users = new Users.model(userData);
users.save(function(err, data){
if (err) return res.json(err, 400);
res.json(data, 201);
});
}
When running create method, the entry is saved to the Mongodb collection but the callback is never reached. Can someone please help me on this track, as I found similar questions but none helped me though. Thanks!
I suppose your are using Express. According Express docs you are calling res.json using incorrect parameters (wrong order).
Correct format:
res.json(code, data)
Example:
res.json(500, { error: 'message' })

Resources