What is the best way to seed data in nodejs mongoose - javascript

I need to seed data into the database in my application. What is the best way to do that? Where should I write the code for seeding the data? what should be the folder structure for this?
I am a rails developer and rails framework has a nice way of seeding the data in seeds.rb, and I want to achieve the same thing in my node.js application.
Since I am new to node.js, I am confused between different available resources on the web.

First create your model in models folder.
models/product.js
const mongoose = require("mongoose");
const productSchema = new mongoose.Schema({
image: { type: String, required: true },
title: { type: String, required: true },
author: { type: String, required: true },
description: { type: String, required: true },
price: { type: Number, required: true }
});
const Product = mongoose.model("Product", productSchema);
module.exports = Product;
Then create a seeder folder
seeder/seedProducts.js
const Product = require("../models/product");
const mongoose = require("mongoose");
const dev = require("../config/dev"); //get your mongoose string
//create your array. i inserted only 1 object here
const products = [
new Product({
image:
"https://static.seattletimes.com/wp-content/uploads/2018/01/a8e801dc-f665-11e7-bf8f-ddd02ba4a187-780x1181.jpg",
title: "Origin",
author: "Dan Brown",
description:
"2017 mystery thriller novel. Dan Brown is back with another thriller so moronic you can feel your IQ points flaking away like dandruff",
price: 12
}),]
//connect mongoose
mongoose
.connect(String(dev.db), { useNewUrlParser: true })
.catch(err => {
console.log(err.stack);
process.exit(1);
})
.then(() => {
console.log("connected to db in development environment");
});
//save your data. this is an async operation
//after you make sure you seeded all the products, disconnect automatically
products.map(async (p, index) => {
await p.save((err, result) => {
if (index === products.length - 1) {
console.log("DONE!");
mongoose.disconnect();
}
});
});
Finally you will run seedProducts.js on the terminal only once.
node seedProducts.js

You can use the mongoose-data-seed package to handle this job.
https://github.com/sharvit/mongoose-data-seed
With mongoose-data-seed you are basically creating seeders files that look like that:
import { Seeder } from 'mongoose-data-seed';
import { User } from '../server/models';
const data = [{
email: 'user1#gmail.com',
password: '123123', password_confirmation: '123123',
isAdmin: true
}, {
email: 'user2#gmail.com',
password: '123123', password_confirmation: '123123',
isAdmin: false
}];
class UsersSeeder extends Seeder {
async shouldRun() {
const usersCount = await User.count().exec();
return usersCount === 0;
}
async run() {
return User.create(data);
}
}
export default UsersSeeder;

Related

I get this error: this.$__.validationError = new ValidationError(this)

I am new to learning web dev using node.js and express.js. When I test my code in Postman the server crashes and gives me this error this.$__.validationError = new ValidationError(this).
I am creating backend server connected to MongoDB and the mongoose package.
Routes
const express = require('express')
const router = express.Router()
const {
create
} = require('./../controllers/courseControllers')
const {verifyAdmin, verify} = require('./../auth')
router.post('/create', verifyAdmin, async (req, res) => {
// console.log(req.body)
try{
create(req.body).then(result => res.send(result))
}catch(err){
res.status(500).json(err)
}
})
Controllers
const Course = require('../models/Course');
//CREATE A COURSE
module.exports.create = async (reqBody) => {
const {courseName, description, price} = reqBody
let newCourse = new Course({
courseName: courseName,
description: description,
price: price
})
// console.log(newCourse)
return await newCourse.save().then((result, err) => result ? result : err)
}
Schema
const mongoose = require('mongoose');
const courseSchema = new mongoose.Schema({
courseName: {
type: String,
required: [true, `Course name is required`],
unique: true
},
description: {
type: String,
required: [true, `Course description is required`]
},
price: {
type: Number,
required: [true, `Price is required`]
},
isOffered: {
type: Boolean,
default: true
},
enrollees: [
{
userId: {
type: String,
required: [true, `userId is required`]
},
enrolledOn: {
type: Date,
default: new Date()
}
}
]
}, {timestamps: true})
module.exports = mongoose.model("Course", courseSchema);
Given the information you provided, i can say that you are missing the enrollees parameter on creation whitin the controller, as enrollees has been set to required, i hope its usefull for you, if not let me know.

Can't pass multiple documents in an array when using findById

I want to find each of the elements in the array by their id and send it with the post request to create a new post. Right now when I create a new post only passes the first index of the array and if I use find() it passes all of the social schemas regardless if it is in the body of the request. I hope this makes sense if it doesn't please let me know. I hope someone can help.
Below is the mongoose schema for the qrcode post also using Joi
const Joi = require("joi");
const mongoose = require("mongoose");
const { themeSchema } = require("./Theme");
const { userSchema } = require("./User");
const { socialSchema } = require("./Social");
const QrCode = mongoose.model(
"QrCode",
new mongoose.Schema({
user: {
type: userSchema,
required: true,
},
name: {
type: String,
maxLength: 255,
required: true,
trim: true,
},
theme: {
type: themeSchema,
required: true,
},
// Social Media Links
social: [
{
type: socialSchema,
required: true,
},
],
})
);
function ValidateQrCode(qrCode) {
const schema = {
userId: Joi.objectId(),
name: Joi.string().max(255).required(),
themeId: Joi.objectId().required(),
socialId: Joi.array().required(),
};
return Joi.validate(qrCode, schema);
}
module.exports.QrCode = QrCode;
module.exports.validate = ValidateQrCode;
this is the post route to create a new qrcode
router.post("/", auth, async (req, res) => {
const { error } = validate(req.body);
if (error) res.status(400).send(error.details[0].message);
const theme = await Theme.findById(req.body.themeId);
if (!theme) return res.status(400).send("Invalid theme.");
const user = await User.findById(req.user._id);
if (!user) return res.status(400).send("Invalid theme.");
const social = await Social.findById(req.body.socialId);
if (!social) return res.status(400).send("Invalid social.");
const qrCode = new QrCode({
user: user,
name: req.body.name,
theme: theme,
social: social,
});
await qrCode.save();
res.send(qrCode);
});
In the body of my Postman request I am inputting the info below
{
"name": "Friends",
"themeId": "60f89e0c659ff827ddcce384",
"socialId": [
"60f89e43659ff827ddcce386",
"60f89e5c659ff827ddcce388"
]
}
To fetch data using ids, you can use below mongodb query simply,
db.collection.find( { _id : { $in : ["1", "2"] } } );
In mongoose,
model.find({
'_id': { $in: [
mongoose.Types.ObjectId('1'),
mongoose.Types.ObjectId('2'),
mongoose.Types.ObjectId('3')
]}
}, function(err, docs){
console.log(docs);
});
Or
await Model.find({ '_id': { $in: ids } });

Express.js blogging application bug: filtering posts by category throws "Cast to ObjectId failed" failed error

I am working on a blogging application (click the link to see the GitHub repo) with Express, EJS and MongoDB.
I have Posts that are grouped into Categories, each in its own collection.
I run into a problem trying to filter posts by category. To obtain the post by category url, I turn the category name into a slug and use it this way:
Posted in <%= post.category.cat_name %>
In the public routes file I have:
const express = require('express');
const postsController = require('../../controllers/front-end/posts');
// Express router
const router = express.Router();
// Get Posts
router.get('/', postsController.getPosts);
// Get Single Post
router.get('/:id', postsController.getSinglePost);
// Get Posts by Category
router.get('/:catname', postsController.getPostsByCategory);
module.exports = router;
The Post model:
const mongoose = require('mongoose');
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
short_description: {
type: String,
required: true
},
full_text: {
type: String,
required: true
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Category'
},
post_image: {
type: String,
required: false
},
updated_at: {
type: Date,
default: Date.now()
},
created_at: {
type: Date,
default: Date.now()
}
});
module.exports = mongoose.model('Post', postSchema);
The Category model:
const mongoose = require('mongoose');
const categorySchema = new mongoose.Schema({
cat_name: {
type: String,
required: true
},
updated_at: {
type: Date,
default: Date.now()
},
created_at: {
type: Date,
default: Date.now()
}
});
module.exports = mongoose.model('Category', categorySchema);
In the Posts controller I turn the slug back into category name to filter posts by category name:
exports.getPostsByCategory = (req, res, next) => {
function titleize(slug) {
var words = slug.split("-");
return words.map(function(word) {
//return word;
return word.charAt(0).toUpperCase() + word.substring(1).toLowerCase();
}).join(' ');
}
const postCategory = titleize(req.params.catname);
const posts = Post.find({ cat_name: postCategory }, (err, posts) => {
console.log('Category: ', postCategory);
if(err){
console.log('Error: ', err);
} else {
res.render('default/index', {
moment: moment,
layout: 'default/layout',
website_name: 'MEAN Blog',
page_heading: 'XPress News',
page_subheading: 'A MEAN Stack Blogging Application',
posts: posts.reverse(),
});
}
}).populate('category');
};
The line console.log('Category: ', postCategory) outputs Category: Favicon.ico instead of the category name.
What am I doing wrong?
if I read this correctly, res is expect json pairs.
I am guessing your post.reverse() does not output in json format.
first of all - look at the moment where you ask DB - you need to await the answer, so you should use Promise.than() or async/await in your routes ...
Another one from request you get STRING as parameter - but in mongo schema you have Object...
So you should receive smth like "CastError: Cast to ObjectId failed...",
it depends on your vision you can: first select category from category.db => so you receive category Object after that you can search the posts using this object ..., or you can first populate results of posts by category (obtain plain category fields) and make further search...
category in your post-schema is a $ref to the category-schema, which is why it holds an objectId. In order to reference and actually query your category-schema while using .find(), you need to populate it first:
Post.
find({}).
populate({
path: 'category',
match: { cat_name: postCategory}
}).
exec((err, posts) => {
// ...
});
The mongoose documentation for $ref/populate() is a bit hidden here, in case you want know more about it.
Thanks to Lilian Baxan, here is the right getPostsByCategory method in controllers\front-end\posts.js:
const Category = require('../../models/categories');
//more code here
exports.getPostsByCategory = async (req, res, next) => {
function titleize(slug) {
var words = slug.split("-");
return words.map(function(word) {
//return word;
return word.charAt(0).toUpperCase() + word.substring(1).toLowerCase();
}).join(' ');
}
const postCategory = titleize(req.params.catname);
const singleCategory = await Category.findOne({cat_name:postCategory})
const posts = await Post.find({ category : singleCategory }, (err, posts) => {
if (err) {
console.log('Error: ', err);
} else {
res.render('default/index', {
moment: moment,
layout: 'default/layout',
website_name: 'MEAN Blog',
page_heading: 'XPress News',
page_subheading: 'A MEAN Stack Blogging Application',
posts: posts.reverse(),
});
}
}).populate('category');
};

Mongoose - When returning all items from a collection (with no search param) the returned items from the collection do not contain their mongo _id

I am having a bit of an issue with Mongoose/MongoDB this afternoon. I have a situation where I need to return all items from a collection, and doing so means that I do not pass in any search params to mongoose.find().
This is the controller that handles the get all request:
exports.get_all_posts = async (req, res, next) => {
const { params } = req;
const { sortby } = params;
//Sortby param takes two arguments for now: most_recent, oldest
try {
const getAllPosts = await BlogPost.find({}, { _id: 0 });
console.log(getAllPosts);
if (!getAllPosts) throw new Error('Could not get blog posts.');
res.json({
posts: date_.sort(getAllPosts, sortby)
});
} catch (error) {
next(error);
}
};
This is particularly where I think the issue is coming from:
const getAllPosts = await BlogPost.find({}, { _id: 0 });
I am passing an empty search parameter and then removing the _id so that it doesn't throw an error telling me that I need to provide the _id.
However I still need to be able to pull in all of the posts. My items from this collection return as normal, just without their _id's.
Here is my model for the blog posts:
const mongoose = require('mongoose');
const BlogPostSchema = new mongoose.Schema({
date: {
type: Date,
required: true
},
title: {
type: String,
required: true
},
author: {
type: String,
required: true
},
likes: {
type: Number,
required: false
},
post_body: {
type: String,
required: true
},
description: {
type: String,
required: true
},
tags: [
{
type: String,
required: false
}
],
featuredImage: {
type: String,
required: false
},
draft: {
type: Boolean,
required: true
}
});
module.exports = mongoose.model('BlogPost', BlogPostSchema);
One thing to note is that I have not defined an _id. Mongoose automatically adds in the _id field before saving a schema, so I think it is okay without it, as it has been in the past.
Thanks in advance for reading and any input!
Just as Joe has commented, { _id: 0 } as the second parameter is making your query not return the _id field.
Also as he said, there should be no problem whatsoever with using find({}).
Since other than what has already been stated, I couldn't figure out any mistake in the code snippets you provided, I guess this error could be coming from somewhere else in your project.
exports.get_all_posts = async (req, res, next) => { const { params } = req; const { sortby } = params;
try { const getAllPosts = await BlogPost.find({}); console.log(getAllPosts); if (!getAllPosts) throw new Error('Could not get blog posts.'); res.json({ posts: date_.sort(getAllPosts, sortby) }); } catch (error) { next(error); } };
no need to {_id:0} in the find() method because this method retrieve all the documents in the db collection

Node.js, MongoDB error - "message": "Schema hasn't been registered for model \"Category\".\nUse mongoose.model(name, schema)"

I'm in process of an app based on Node.js, MongoDB and Express. My goal is to get a fetch API system to work.
When using Postman to check out my status, the GET for "article.js" model file (in my localhost:3000/articles) shows the following error:
{
"error": {
"message": "Schema hasn't been registered for model \"Category\".\nUse mongoose.model(name, schema)",
"name": "MissingSchemaError"
}
}
This error disables the display of my articles or categories in Postman, as they are saved in my MongoDB project area at mongodb cloud.
The model file code "article.js" is the following:
const mongoose = require('mongoose');
const articleSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
title: { type: String, required: true },
description: { type: String, required: true },
content: { type: String, required: true },
categoryId: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'Category' }
});
module.exports = mongoose.model('Article', articleSchema);
This file connects with the controller named "articles.js", with the following relevant code:
const mongoose = require('mongoose');
const Article = require('../models/article');
const Category = require('../models/category');
module.exports = {
getAllArticles: (req, res) => {
Article.find().populate('categoryId', 'title').then((articles) => {
res.status(200).json({
articles
})
}).catch(error => {
res.status(500).json({
error
})
});
},
createArticle: (req, res) => {
const { title, description, content, categoryId } = req.body;
Category.findById(categoryId).then((category) => {
if (!category) {
return res.status(404).json({
message: 'Category not found'
})
}
const article = new Article({
_id: new mongoose.Types.ObjectId(),
title,
description,
content,
categoryId
});
return article.save();
}).then(() => {
res.status(200).json({
message: 'Created article'
})
}).catch(error => {
res.status(500).json({
error
})
});
},
}
The model file "category.js" code in the app looks like this:
const mongoose = require('mongoose');
const categorySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
title: { type: String, required: true },
description: { type: String, required: true }
});
module.exports = mongoose.model('Category', categorySchema);
I looked up topics from the past here, such as this one - but it didn't solve my problem.
What should I do in order to fix my code?
Is it a syntax mistake or something else?
the code seems to be OK
I don't see here any particular error's

Categories

Resources