How to create multiple collections and send posts dynamically in mongodb / mongoose - node.js

Basically I am trying to make a to-do-app which will be based on the CITY that a user submits from, if they submit from VANCOUVER, then I want there to be a collection created named VANCOUVER and the post to be submitted there, then I can collect posts from that collection, the reason being performance when I begin to add query , so I dont have to query alot of the posts if I just need info from 1 city.
I did read the docs and current I am experimenting, would love some input here.
If someone can point me to some articales or guides / good doc points, I would love that or just help me if I am going the right way , or perhaps I should be looking at the problem in a different light?
This is my current route file
const express = require('express');
const router = express.Router();
// Schema import
const postModel = require('../models/postModel');
const vancouver = require('../models/cityModel');
const toronto = require('../models/cityModel');
const victoria = require('../models/cityModel');
const mongoose = require('mongoose');
// this should return all of the posts inside of a single city
// wildcard could be vancouver or toronto for example
router.get('/:wildcard', (req, res, next) => {
req.params.wildcard.find((error, returnedDocuments) => {
if (error) return next(error);
res.json(returnedDocuments);
});
});
// this should delete a single post, via an ID identification , inside of a specific city
// the city will be set on the user side
router.delete('/:wildcard', (req, res, next) => {
req.params.wildcard.findByIdAndRemove(req.query.postid, (error, returnedDocuments) => {
if (error) return next(error);
res.json(returnedDocuments);
});
});
router.post('/:wildcard', (req, res, next) => {
req.body.wildcard.create({ post: req.body.post }, (error, returnedDocuments) => {
if (error) {
throw new Error(error);
}
});
});
module.exports = router;
the city mode is basically just the city name, and has an array for posts, these will be queried based on the category that the user wants to access
const citySchema = new mongoose.Schema(
{
name: { type: String },
posts: { type: Array }
},
{
timestamps: true
}
);
module.exports = mongoose.model('city', citySchema);

You can parameterize the model-generation:
const express = require('express');
const router = express.Router();
// Schema import
const postModel = require('../models/postModel');
const citySchema = require('../models/citySchema');
const mongoose = require('mongoose');
const getModel = (name) => mongoose.modelNames().contains(name) ? mongoose.model(name, citySchema) : mongoose.model(name)
router.get('/:wildcard', (req, res, next) => {
// You should add some validation on the wildcard before using it directly here
getModel(req.params.wildcard).find((error, returnedDocuments) => {
if (error) return next(error);
res.json(returnedDocuments);
});
});
// ...
module.exports = router;
citySchema:
const citySchema = new mongoose.Schema(
{
name: { type: String },
posts: { type: Array }
},
{
timestamps: true
}
);
module.exports = citySchema;
A thing to note is that you are risking creating arbitrarily many models and collections, which might have some performance impact as well.

Related

Attribute not submitting to MongoDB (MERN stack)

I'm working on an app that assesses students algebra 1 level. I'm trying to send a string called "answers" to the database, but nothing is ever sent. I've shown the model/schema below, where basically each submission should send the answers String (it was originally an object, but I couldn't get an answer to Mongoose not persisting object so I'm just trying a string to see if it even submits a string. The user and date are submitted to the database, but there is not even an entry for the answers attribute. I've seen that the payload sent if I submit a "2" is {"results": "2"} so there's something in the request body. My response back from the server is {} so I think I'm not destructuring a prop correctly or maybe sending an object unintentionally.. Any ideas as to why no answers attribute is submitted to the database? Any help is greatly appreciated!
api/algebra1.js (route to send test results)
const express = require('express');
const router = express.Router();
var bodyParser = require('body-parser')
const bcrypt = require('bcryptjs');
const algebra1 = require('../../models/Algebra1');
const jwt = require('jsonwebtoken');
const config = require('config');
const auth = require('../../middleware/auth');
//#route POST api/auth
//#desc Algebra 1 route
//#access Private
var jsonParser = bodyParser.json();
router.post('/', [jsonParser, auth], async (req, res) => {
const { answers } = req.body;
try {
let newTest = new algebra1({
answers: answers,
user: req.user.id,
date: Date.now()
})
console.log("body is " + req.body)
await newTest.save();
res.json({ answers: answers });
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
})
module.exports = router;
Algebra1.js (model for Mongoose):
const mongoose = require('mongoose');
const Algebra1Schema = new mongoose.Schema({
answers: {
type: String
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
},
date: {
type: Date,
default: Date.now
}
})
module.exports = algebra1 = mongoose.model('algebra1', Algebra1Schema)
submit action (submits results to api/algebra1 route):
export const submit = (results) => async dispatch => {
try {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
console.log(results);
const body = JSON.stringify({ results });
const res = await axios.post('/api/algebra1', body, config);
dispatch({
type: QuestionActionTypes.RESET
})
dispatch(setAlert('You\;ve finished your assessment!', 'success'));
} catch (err) {
console.error(err.message);
}
}
You are sending data with results key and destructing as answer key. Where are you sending anything against answer key ? I guess you meant to submit results as answers.
const body = JSON.stringify({ answers: results });

Mongoose query between values Express Js

am playing with MongoDb and Mongoose, and I am trying to filter by price range, for example display properties from 0 to any number (10000),
My model is very simple:
const mongoose = require('mongoose');
const PropertySchema = mongoose.Schema({
title: String,
description: String,
price: Number,
town: String
})
module.exports = mongoose.model('Property', PropertySchema);
And route. this what am up to, set price from 0 to any number, I don’t want to hard-code this max value
const express = require('express');
const router = express.Router();
const Property = require('../models/Property');
router.get('/', async (req, res) => {
try {
const properties = await Property.find({ price: { $in: [ 0, 0 ] } });
res.json(properties);
} catch (err) {
res.json({ message: err });
}
});
URL
properties?price=0&10000
Can anybody help me with this? How can I set range of price for properties?
You need to pass both priceMin & priceMax from queryParams & use same in your query
const express = require('express');
const router = express.Router();
const Property = require('../models/Property');
router.get('/', async (req, res) => {
try {
const properties = await Property.find({ price: { $gte:req.query.priceMin, $lte: req.query.priceMax } });
res.json(properties);
} catch (err) {
res.json({ message: err });
}
});
URL
properties?priceMin=0&priceMax=10000
You can do this using $gt and $lt
properties?min=0&max=10000
router.get('/', async (req, res) => {
let min = req.query.min;
let max = req.query.max;
try {
const properties = await Property.find({ price: { $gt : min , $lt : max } });
res.json(properties);
} catch (err) {
res.json({ message: err });
}
});

Error running mongoose update code ( router.patch() )

I'm getting an error running router.patch() code to update a product on a cloud-based mongoose database. I'm using Postman to simulate the update. Postman's error is showing, "req.body[Symbol.iterator] is not a function." Here is the relevant code:
Products.js:
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const Product = require('../models/product');
router.patch('/:productId', (req, res, next) => {
const id = req.params.productId;
// don't want to update both fields if not needed
const updateOps = {};
// loop through all the operations of the request body
for (const ops of req.body) {
updateOps[ops.propName] = ops.value;
}
Product.update({_id: id}, { $set: updateOps })// $set is a mongoose object
.exec()
.then(result => {
console.log(result);
res.status(200).json(result);
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
{req.body.newName, price, req.body.newPrice} ;
res.status(200).json({
message: 'Updated product',
});
});
module.exports = router
Product.js:
const mongoose = require('mongoose');
const productSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: String,
price: Number
});
// export the schema into the Mongoose model
module.exports = mongoose.model('Product', productSchema);
Any help would be greatly appreciated. :-)
As I commented, this part is likely your problem:
for (const ops of req.body) {
updateOps[ops.propName] = ops.value;
}
Since req.body is an Object, I think you want:
for (let [key, value] of Object.entries(req.body)){
updateOps[key.propName] = value;
}
Or something similar.

node server crashing when validation error occurs with mongoose

I have created a dynamic schema for every user with node and mongoose as given below.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
require('mongoose-currency').loadType(mongoose);
var Currency = mongoose.Types.Currency;
var values = 'Credit Debit'.split(' ');
var schema = new Schema({
amount: {
type: Currency,
required: true
},
type: {
type: String,
enum: values
},
description: {
type: String,
required: true
}
},
{
timestamps: true
});
exports.create_database = function(mobile) {
return mongoose.model('personal_'+mobile, schema, 'personal_'+mobile);
};
I have used this in a personal router code given below
var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var database = require('../models/personal');
var Verify = require('./verify');
var personalRouter = express.Router();
personalRouter.use(bodyParser.json());
personalRouter.route('/')
.get(Verify.verifyOrdinaryUser, function (req, res, next) {
var mobile = req.decoded._doc.mobile;
var Personal = database.create_database(mobile);
Personal.find(req.query)
.exec(function (err, personal) {
if (err) next(err);
res.json(personal);
})
})
.post(Verify.verifyOrdinaryUser, function(req, res, next) {
var mobile = req.decoded._doc.mobile;
var Personal = database.create_database(mobile);
Personal.create(req.body, function(err, personal) {
if(err) next(err);
console.log('Personal Record added!');
var type = personal.type;
var amount = personal.amount/100;
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Added the '+type+' record of amount = '+amount);
})
})
module.exports = personalRouter;
Now everything works good withe the get and the post routers untill i pass in values which do not go with the mongoose schema.
Eg. If i pass in the value as say without a description my server will give a validation error and crash.
I tried replacing next(err) with throw(err in the code without any luck.
I want the error to be displayed and prevent the server from crashing and shutting down.
Please help me, where am i going wrong?

trying to display data in jade from mongodb

trying to display data from mongoose schema to jade temaplate but it dosent work no matter what i try , so please help me and thanks .
first here is my book schema models/book.js
const mongoose = require('mongoose')
const schema = mongoose.Schema
const BookSchema = new schema({
title: String,
author: String,
isbn: Number,
date: { type: Date, default: Date.now},
description: String
})
module.exports = mongoose.model('Book', BookSchema)
and here is my controller for the book model
const Book = require('../models/book')
const express = require('express')
router = express.Router()
router.route('/books')
// Create a book
.post( (req, res) => {
const book = new Book()
book.name = req.body.name
book.save( (err) => {
if (err)
res.send(err)
console.log('Book created! ')
})
})
//get all books
.get( (req, res) => {
Book.find( (err, books) => {
if (err)
res.send(err)
res.render('books', {title: 'books list'})
})
})
module.exports = router
and at last here is my jade template
extends layout
block content
if books
each book in books
h1 #{book.title}
There are multiple mistakes/modifications required in your code.
while finding, its better to give {} as first input.
When rendering the book template, you are using books variable to show list of books, but you are not sending it from the route. you need to send books in res.render.
Try this:
router.route('/books')
// Create a book
.post( (req, res) => {
const book = new Book()
book.name = req.body.name
book.save( (err) => {
res.send(err)
console.log('Book created! ')
})
})
//get all books
.get((req, res) => {
Book.find({},(err, books) => {
if (err)
res.send(err)
res.render('books', {title: 'books list' , books : books})//need to send the books variable to the template.
})
})

Resources