Sequelize: create is not a function when model is generated from migration - javascript

I created this model from sequelize CLI
models/society.js
'use strict';
module.exports = (sequelize, DataTypes) => {
const Society = sequelize.define('Society', {
code: DataTypes.STRING,
name: DataTypes.STRING,
description: DataTypes.STRING
}, {});
Society.associate = function(models) {
// associations can be defined here
};
return Society;
};
Then this is my index.js file for configurations
'use strict'
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const api = require('./routes')
app.use(bodyParser.urlencoded({extended: false}))
app.use(bodyParser.json())
app.use('/api', api)
const port = process.env.PORT || 3000
app.listen(port, ()=>{
console.log(`API REST running on http://localhost:${port}`)
})
The part of routes is this
routes/index.js
'use strict'
const express = require('express')
const api = express.Router()
const SocietyCtrl = require('../controllers/society')
api.post('/society', SocietyCtrl.createSociety)
module.exports = api
And finally it's just the controller
controllers/society.js
'use strict'
const Society = require('../models/society')
function createSociety(req, res){
console.log('POST /api/society/')
Society.create(req.body).then(created =>{
res.status(200).send({society: created})
})
}
module.exports = {
createSociety
}
The problem comes when I try to make POST, I get this following error:
Society.create is not a function
Can you tell me what I'm doing wrong?

This problem is not related to migration, however to solve this problem you have to do two steps:
1) Add new file in models directory called index.js which contain the following code
NOTE: make sure to edit sequelize config (with your environment) which starts in line 9 and ends in line 13 in file below (models/index.js)
'use strict';
const Sequelize = require('sequelize');
const fs = require('fs');
const path = require('path');
const basename = path.basename(__filename);
const db = {};
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
port: 3066,
dialect: /* one of 'mysql' | 'mariadb' | 'postgres' | 'mssql' */
});
fs.readdirSync(__dirname).filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
}).forEach(file => {
const model = sequelize['import'](path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
module.exports = db;
2) in controllers/society.js file do the following
replace const Society = require('../models/society'); with const db = require('../models/index'); or const db = require('../models');
replace Society.create with db.Society.create
like this:
'use strict'
const db = require('../models');
function createSociety(req, res){
console.log('POST /api/society/');
db.Society.create(req.body).then(created =>{
res.status(200).send({society: created})
});
}
module.exports = {
createSociety
}
To learn more I recommend you to check a github repository called express-example which developed by official sequelize team

Thanks Amjed!
But I didn't need to add index.js to models directory because sequelize already did.
However all I needed to do was:
'use strict'
const db = require('../models/index')
const Society = db.Society
And then it worked like it was supposed to.

Related

req.body is undefined in REST API using Express JS,

I am trying to create a REST API using Express JS.
console.log(req.body) gives undefined as output,
this is my code in routes.js page
const express = require('express');
const router = express.Router();
router.post('/post',async (req,res) => {
console.log("inside post router");
console.log(req.body);
const data = new Model({
name: req.body.name,
age: req.body.age
})
try {
const dataToSave = await data.save();
res.status(200).json(dataToSave)
}
catch(error) {
res.status(400).json({message:error.message})
}
})
This is the code in index.js file
const express = require('express');
const mongoose = require('mongoose');
const routes = require('./Routes/routes');
const app = express();
app.use('/api',routes);
User middlewares ,for parsing the post body in your index.js file
const express = require('express');
const mongoose = require('mongoose');
const routes = require('./Routes/routes');
const app = express();
app.use(express.json()) ; //parsing application/json
app.use(express.urlencoded({extended: false}) ;
app.use('/api',routes);
Make sure to use them ,before you configure your routes
See reference

nodejs : nodemon app crashed - waiting for file changes before starting

I was actually following a nodejs course on Udemy and suddenly down the course, the code started breaking and giving some errors. I then tried copying the instructor's code, but still, the problem was the same.
I also followed this answer on StackOverflow itself but the problem remains the same.
I am attaching all the js files below and also the error message from the terminal below:
Error message from the terminal
This is what the file structure looks like
Now the js files:
app.js file:
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const adminRoutes = require('./routes/admin');
const shopRoutes = require('./routes/shop');
const errorController = require('./controllers/error');
const app = express();
app.set('view engine', 'ejs');
app.set('views', 'views');
app.use(bodyParser.urlencoded({extended:false}));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/admin', adminRoutes);
app.use(shopRoutes);
app.use(errorController.get404Page);
app.listen(3000);
controllers/error.js file:
exports.get404 = (req, res, next) => {
res.status(404).render('404', { pageTitle: 'Page Not Found' });
};
controllers/products.js file
const Product = require('../models/product');
exports.getAddProduct = (req, res, next) => {
res.render('add-product', {
pageTitle: 'Add Product',
path: '/admin/add-product',
formsCSS: true,
productCSS: true,
activeAddProduct: true
});
};
exports.postAddProduct = (req, res, next) => {
const product = new Product(req.body.title);
product.save();
res.redirect('/');
};
exports.getProducts = (req, res, next) => {
Product.fetchAll(products => {
res.render('shop', {
prods: products,
pageTitle: 'Shop',
path: '/',
hasProducts: products.length > 0,
activeShop: true,
productCSS: true
});
});
};
models/product.js file :
const fs = require('fs');
const path = require('path');
const p = path.join(
path.dirname(process.main.filename),
'data',
'products.json'
);
const getProductsFromFile = cb => {
fs.readFile(p, (err, fileContent) => {
if (err) {
cb([]);
} else {
cb(JSON.parse(fileContent));
}
});
};
module.exports = class Product {
constructor(t) {
this.title = t;
}
save() {
getProductsFromFile(products => {
products.push(this);
fs.writeFile(p, JSON.stringify(products), err => {
console.log(err);
});
});
}
static fetchAll(cb) {
getProductsFromFile(cb);
}
};
routes/admin.js file:
const path = require('path');
const express = require('express');
const productsController = require('../controllers/products');
const router = express.Router();
// /admin/add-product => GET
router.get('/add-product', productsController.getAddProduct);
// /admin/add-product => POST
router.post('/add-product', productsController.postAddProduct);
module.exports = router;
routes/shop.js file:
const path = require('path');
const express = require('express');
const productsController = require('../controllers/products');
const router = express.Router();
router.get('/', productsController.getProducts);
module.exports = router;
util/path.js file:
const path = require('path');
module.exports = path.dirname(process.main.filename);
I am new to backend development, nodejs to be specific. Please help me find my mistake.
In many file you have used process.main.filename, but there is no property named process.name for node.js process, so process.main is undefined. As a result reading the property process.main.filename gives the error.
So, to solve your problem:
Replace every process.main.filename with
process.mainModule.filename OR require.main.filename
(there is difference in both, but it will not matter in your app.)
and see if it works. I guess this is a mistake on your part while writing the code.
Tip: Always try to understand the error using terminal output. That way You can solve most of the problems.

CRUD - I can't insert data using express and mongodb

I am trying to insert a category in the database following the instructions of a course I am taking and I am unable to insert it with the create method. It shows ... loading in Postman and nothing happens and no error message appears on the console. Here are my files.
app.js
const express = require('express')
const mongoose = require('mongoose')
const morgan = require('morgan')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const expressValidator = require('express-validator')
require('dotenv').config()
//import routes
const authRoutes = require('./routes/auth')
const userRoutes = require('./routes/user')
const categoryRoutes = require('./routes/category')
// app
const app = express()
// db
mongoose.connect(process.env.DATABASE, {
useNewUrlParser: true,
useCreateIndex: true
})
.then(() => console.log('DB Connected'))
// middlewares
app.use(morgan('dev'))
app.use(bodyParser.json())
app.use(cookieParser())
app.use(expressValidator())
// routes middleware
app.use('/api', authRoutes)
app.use('/api', userRoutes)
app.use('/api', categoryRoutes)
const port = process.env.PORT || 8000
app.listen(port, () => {
console.log(`Server is running on port ${port}`)
})
routes/category.js
const express = require('express')
const router = express.Router()
const { create } = require('../controllers/category')
const { requireSignin} = require('../controllers/category')
const { userById } = require('../controllers/user')
router.post('/category/create/:userId', function(req, res){
requireSignin,
create
});
router.param("userId", userById)
module.exports = router
controllers/category.js
const Category = require("../models/category")
const { errorHandler } = require("../helpers/dbErrorHandler")
exports.create = (req, res) => {
const category = new Category(req.body)
category.save((err, data) => {
if(err) {
return res.status(400).json({
error: errorHandler(err)
})
}
res.json({ data })
})
}
models/category.js
const mongoose = require('mongoose')
const categorySchema = new mongoose.Schema(
{
name: {
type: String,
trim: true,
required: true,
maxlength: 32
}
},
{ timestamps: true }
);
module.exports = mongoose.model('Category', categorySchema)
In order to make sure that data is actually being returned, your create function needs to be asynchronous. Adding async/await to the save function should confirm that you are properly saving the data to the database before returning.
It appears you have an error in your route setup. I assume requireSignin and create should be middleware functions.
So instead of
router.post('/category/create/:userId', function(req, res){
requireSignin,
create
});
you should try this
router.post('/category/create/:userId', requireSignin, create);
// assuming 'create' is the last one, since you are ending the request there
// also assuming that 'requireSignin' is setup as middleware, calling next function

Route.delete() requires a callback function but got a [object Object]

I have node-express app where I have bunch of Routes for login, logout and signup and one Route for checking authorised Route which can be accessed only through providing authToken. I moved the Routes to separate Route file and I got the above error.
This is my Users Routes File:
const express = require('express');
const authenticate = require('./../middleware/authenticate');
const router = express.Router();
const {User} = require('./../models/user');
router.post('/',(req, res) => {
var body = _.pick(req.body,['email','password']);
var user = new User(body);
user.save().then(() => {
return user.generateAuthToken()
}).then((token) => {
res.header('x-auth', token).send(user);
}).catch((e) => {
res.status(400).send(e);
});
});
router.post('/login',(req, res) => {
var body = _.pick(req.body, ['email', 'password']);
User.findByCredentials(body.email, body.password).then((user) => {
return user.generateAuthToken().then((token) => {
res.header('x-auth', token).send(user);
});
}).catch((e) => {
res.status(400).send(e);
});
});
router.delete('/logout',authenticate, (req, res) => {
req.user.removeToken(req.token).then(() => {
res.status(200).send();
},(e) => {
res.status(400).send(e);
}) ;
});
router.get('/me',authenticate, (req,res) => {
res.send(req.user);
});
module.exports = router;
Following is my main server.js file:
const express = require('express');
const _ = require('lodash');
var app = express();
const usersRoutes = require('./routes/users');
app.use(express.json());
app.use('/users', usersRoutes);
var {mongoose} = require('./db/mongoose');
var {User} = require('./models/user');
var {authenticate} = require('./middleware/authenticate');
const port = process.env.PORT || 3000 ;
app.listen(port, () => console.log(`Listening on ${port}...`))
I have a model/Schema(mongoose) file for User so If You feel you need that I am ready to edit my question. Thanks.
The problem is that router.delete is expecting a function on the middleware parameter (like you did in your server.js file with app.use(express.json())) so it can be used like a callback which gets called whenever a request reach your route.
Try changing authenticate to authenticate().
It seems like in your users routes file you are importing the entire module who contains the authenticate function, so when try to access it like a function you'll get an error. You need to import it like you did in your server.js file.
Change the line const authenticate = require('./../middleware/authenticate'); for const {authenticate} = require('./../middleware/authenticate');.

Vue.js server side rendering generated bundle is undefined

I am trying to get server side rendering set up in a Vue application. I have imported the server side renderer bundle and I believe included everything necessary for it to work, however, when refreshing my webpage I am getting the error Cannot read property 'renderToString' of undefined from my server.js file.
I've tried to debug but it appears as though my bundle never gets set to anything and so is always undefined.
dev-server.js
const webpack = require('webpack')
const clientConfig = require('./webpack.client.config')
const serverConfig = require('./webpack.server.config')
const MFS = require('memory-fs')
const path = require("path")
module.exports = function setupDevServer (app, onUpdate) {
clientConfig.entry.app = [
'webpack-hot-middleware/client',
clientConfig.entry.app
]
clientConfig.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
)
const clientCompiler = webpack(clientConfig)
app.use(
require('webpack-dev-middleware')(clientCompiler, {
stats: {
colors: true
}
})
)
app.use(require('webpack-hot-middleware')(clientCompiler))
const serverCompiler = webpack(serverConfig)
const mfs = new MFS()
const outputPath = path.join(serverConfig.output.path, 'server/main.js')
serverCompiler.outputFileSystem = mfs
serverCompiler.watch({}, () => {
onUpdate(mfs.readFileSync(outputPath, 'utf-8'))
})
}
server.js
const express = require("express");
const app = express();
const fs = require("fs");
const path = require("path");
const { createBundleRenderer } = require('vue-server-renderer');
let renderer;
const indexHTML = (() => {
return fs.readFileSync(path.resolve(__dirname, "./index.html"), "utf-8");
})();
app.use("/dist", express.static(path.resolve(__dirname, "./dist")));
require("./build/dev-server")(app, bundle => {
renderer = createBundleRenderer(bundle)
});
app.get("*", (req, res) => {
renderer.renderToString({ url: req.url }, (err, html) => {
if (err) {
return res.status(500).send('Server Error')
}
html = indexHTML.replace('{{ APP }}', html)
res.write(html);
res.end();
})
});
const port = process.eventNames.PORT || 3000;
app.listen(port, () => {
console.log(`server started at http://localhost:${port}`);
});

Categories