Mongoose, creating a new model - node.js

I had model Product, he was added without problem to db "products"
router.post('/create', function (req, res, next) {
console.log(req.body);
var newProduct = {
title: req.body.name,
price: req.body.price,
description: req.body.description,
quantity: req.body.quantity,
// category: req.body.category
}
var product = new Product(newProduct);
product.save(function (err, product) {
if (err) {
res.status(404).json({
message: 'Can not create this product'
})
} else {
console.log('added');
res.send(product);
}
});
});
Now i have model Category i was created http.post and all is working, but I have no idea where this things sended by post are save in database mongo
router.post('/create', function (req, res, next) {
var newCategory = {
name: req.body.name,
description: req.body.description
}
var category = new Category(newCategory);
category.save(function (err, category) {
if (err) {
res.status(404).json({
message: 'Can not create this category'
})
} else {
console.log('added');
res.send(category);
}
});
});
Can someone exaplain me??

As far as mongoose automatically transforms your model name to plurual forms, it should be - categories.
Update:
If you still want your singular naming, you can try something like this:
const Category = mongoose.model('Category ', Category Schema, 'Category ');

Related

return result to parent function from async.parallel node.js

I'm very new to node.js and need help. I need to send save() result to controller, but it is isolated. I do not understand what is the way do do it properly. Should it be a callback (trying to understand how it works) or another solution. Can you please explain how to resolve it on a specific case?
Thank you.
Method called from the Controller:
exports.createProduct = function (req) {
async.parallel({
// Search for genre existent id's sent from client
genres: (callback) => {
Genre.find({_id: {$in: req.body.genre}}, '_id').exec(callback);
}
}, (err, docs) => {
// if (err) { throw err; }
// Assign found genres
req.body.genre = docs.genres;
let product = new Product({
title: req.body.title,
description: req.body.description,
images: req.body.images,
genres: req.body.genre,
price: req.body.price,
status: req.body.status,
sold: req.body.sold,
});
return product.save();
});
// return to Controller
};
You can do it passing a callback function for createProduct function like this
// Product module
exports.createProduct = function (req, callback) {
async.parallel({
// Search for genre existent id's sent from client
genres: (callback) => {
Genre.find({_id: {$in: req.body.genre}}, '_id').exec(callback);
}
}, (err, docs) => {
// if (err) { throw err; }
// Assign found genres
req.body.genre = docs.genres;
let product = new Product({
title: req.body.title,
description: req.body.description,
images: req.body.images,
genres: req.body.genre,
price: req.body.price,
status: req.body.status,
sold: req.body.sold,
});
product.save();
return callback(/* You can pass any params here*/);
});
// return to Controller
};
/// Controller module
const product = require('./lib/product');
exports.controllerFunction = () => {
product.createProduct(req, (params) => {
// Called when product is created
})
}

How do you save to three collections at once?

I'm building my first mean stack app. It's a review site that contains three models: User, Review, and Company.
When I make a review, I want the new review to be saved to the 'review' collection, and for that review to be connected by reference to the company being reviewed and the user who wrote the review. I also want the user to hold a reference to the review, and the company to hold a reference to all the reviews it has. Here are my models:
Review
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const reviewSchema = new Schema ({
companyName: String,
companyId: { type: Schema.Types.ObjectId, ref: 'Company'},
starRating: Number,
subject: String,
commentBody: String,
createdBy: { type: Schema.Types.ObjectId, ref: 'User'},
});
const Review = mongoose.model("Review", reviewSchema);
module.exports = Review;
Company
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const companySchema = new Schema ({
companyName: String,
about: String,
basedIn: String,
materialOrigins: [String],
productRange: [String],
category: String,
reviews: [ {type: Schema.Types.ObjectId, ref: 'Review'} ],
socialRating: Number,
environmentalRating: Number,
priceRange: Number
});
const Company = mongoose.model("Company", companySchema);
module.exports = Company;
User
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema ({
email: String,
firstName: String,
lastName: String,
password: String,
image: Object,
aboutText: String,
reviews: [ { type: Schema.Types.ObjectId, ref: "Review" } ]
// comments: { type: Schema.Types.ObjectId, ref: 'Comment' }
});
const User = mongoose.model("User", userSchema);
module.exports = User;
This is my current route, which currently saves the review to the collection and attaches the user. However, the user doesn't get the review.
route
router.post('/:category/:company', (req, res) => {
var subject = req.body.subject;
var commentBody = req.body.commentBody;
var starRating = req.body.starRating;
var userId = req.body.userId;
if(!subject || !commentBody || !starRating) {
res.status(400).json({ message: "Subject, comment body, and star rating are required." });
return;
}
var newReview = Review({
starRating,
subject,
commentBody,
userId
});
User.findById(userId, {
}, (err, user) => {
if (err) {
return res.send(err);
} else {
console.log("checking out user in route", user);
user.reviews.push(newReview);
user.save();
newReview.save((err, review) => {
if (err) {
return res.status(400).json({ message: err });
} else {
res.status(200).json({ message: 'Review saved', review });
}
});
}
});
I haven't tried adding the company in because I'm trying to do one thing at a time. I've been looking at 'populate', but all of the documentation seems to only use two models at once. Is it possible to do three at once? Or am I overcomplicating this?
Apologies if this is all overcomplicated. I'm fairly new to MongoDB and MEAN stack in general. Thanks for your help.
Ok, I did it, for any people landing on this page wondering the same thing in the future.
Here's my route:
router.post('/:category/:company', (req, res, next) => {
var companyName;
var companyId;
var subject = req.body.subject;
var commentBody = req.body.commentBody;
var starRating = req.body.starRating;
var createdBy = req.body.createdBy;
if(!subject || !commentBody || !starRating) {
res.status(400).json({ message: "Subject, comment body, and star rating are required." });
return;
}
var newReview = Review({
starRating,
subject,
commentBody,
createdBy
});
//I need the companyId and companyInfo for later use in my review save. I'm calling the company with the name I have from my params, and setting the id and name with the received data from Mongo.
Company.findOne({"companyName": req.params.company}, (err, company) => {
if (err) {
return res.status(400).json({ message: err });
} else {
this.companyName = company.companyName;
this.companyId = company.id;
}
});
newReview.save((err, review) => {
//Push the review id to the user
if (err) {
return res.status(400).json({ message: err });
} else { User.findByIdAndUpdate({_id: createdBy },{$push: {reviews: review.id} }, (err) => {
if (err) {
console.log("There was an error pushing review to user");
next(err);
//Push the review id to the company
} else { Company.findOneAndUpdate({ "companyName": req.params.company}, {$push: {reviews: review.id}}, (err, company) => {
if (err) {
console.log("There was an error pushing review to company");
next(err);
} else {
//Updates the review by setting companyId and companyName properties to review for Mongo
Review.update({_id: review.id}, {$set: {companyId: this.companyId, companyName: this.companyName}}, (err, changes) => {
if(err) {
return res.status(400).json({message : err});
} else {
console.log("updating review successfully with company info", changes);
}
});
console.log ("Review successfully saved");
res.json({
review: review,
});
}
});
}
});
}
});
});
If anyone has feedback on how this could be done better/more efficiently, let me know. Cheers.

how can i access mongodb document's array? (mongodb, nodejs)

Hi i have some problems with mongodb.
const mongoose = require('mongoose');
const companySchema = new mongoose.Schema({
name: String,
url: String,
images: Array
});
const categoriesSchema = new mongoose.Schema({
company: companySchema,
name: String
});
module.exports = mongoose.model('categories', categoriesSchema);
above of code is model
app.post('/addCompanyinfo', function (req, res){
var news = new Categories();
news.company[name]= req.body.company; <--- here!
news.save(function (err) {
if(err) {
console.error(err);
res.json({result: 0});
return;
}
res.json({result: 1})
})
})
and this is router code. and i want to access
categoriesSchema-> company (companySchema)-> name.
how can i access company schema's 'name' ??
your help will be a big lucky in future to you :)
You need to create an Object for Company to assign its properties
var news = new Categories();
var company = new Company();
news.company = company;
news.name = 'test category'
company.name = 'test company';
console.log(company);
console log
{ name: 'test category',
company: { _id: 5a61629b74f8df0bd73142ba, images: [] },
_id: 5a61629b74f8df0bd73142b9 }
{ name: 'test company', _id: 5a61629b74f8df0bd73142ba, images: [] }
You can post your data in json format and use bodyParser.json() middleware in your app.js, and your backend code can be this:
router.post('/', function(req, res, next) {
var news = new Categories(req.body); // create record directly with the json data
console.log(req.body.company.name); //just access it directly
news.save(function (err) {
if(err) {
console.error(err);
res.json({result: 0});
return;
}
res.json({result: 1});
});
});
and json format can be this:
{
"company": {
"name": "test company name",
"url": "http://test.com",
"image": []
},
"name": "test name"
}

two way navigation in a mongo one to n relashionship

I'm having hard times with the mongoose relashionship system.
Here are my schemes:
const mongoose = require('mongoose');
const RecipeSchema = mongoose.Schema({
Title: { type: String },
Description: { type: String },
Complaints: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Complaint' }]
});
const Recipe = mongoose.model('Recipe', RecipeSchema);
const ComplaintSchema = mongoose.Schema({
Recipe : { type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' },
Message: { type: String }
});
const Complaint = mongoose.model('Complaint', ComplaintSchema);
And here are how I'm saving my data:
var recipeEntity = new Recipe({
Title: request.body.Title,
Description: request.body.Description
});
recipeEntity.save();
var complaintEntity= new Complaint({
Message: request.body.Message.trim(),
Recipe: mongoose.Types.ObjectId(request.body.Message.RecipeId);
});
complaintEntity.save();
So far, so good... at least to me!
And now, when I try to list the recipes with the complaints, I just got an empty array of complaints:
Recipe
.find()
.populate('Complaints')
.exec(callback);
And here is the json result:
[{
"Id": "595fe6f89d63700011ee144d",
"Title": "Chocolate Cake",
"Description": "aaaa bbb cc d"
"Complaints": []
}]
So, what am I missing here?
tks for your support
I am going to assume that you are not saving both recipe and complaint during the same call. That would not make any sense: everytime you make a complaint, you wouldn't make a recipe too.
When you create a complaint, you need to save its associated recipe's ObjectId AND also add/push the complaint's ObjectId into the associated recipe's complaints.
If you are following resource naming conventions, you would have something like:
// get recipes including complaints
app.get('/recipes', function (req, res) {
Recipe.find().populate('Complaints').exec(function (err, recipes) {
console.log(recipes);
});
});
// add recipe
app.post('/recipes', function (req, res) {
var recipe = new Recipe(req.body); // simplified
recipe.save(function (err) {
if (err)
return res.send(err);
res.send('ok');
});
});
// add complaint for recipe
app.post('/recipes/:recipeID/complaints', function (req, res) {
// we query recipe bc we need it after
Recipe.findById(req.params.recipeID, function (err, recipe) {
if (err)
return res.send(err);
if (!recipe)
return res.send('No recipe found');
// add complaint
var complaint = new Complaint(req.body);
complaint.Recipe = recipe._id; // add reference in one direction
complaint.save(function (err) {
if (err)
return res.send(err);
// update recipe
recipe.Complaints.push(complaint._id); // add reference in other direction
recipe.save(function (err) {
if (err)
return res.send(err);
res.send('ok');
});
});
});
})
I think this is a good read: many to many relationship with nosql (mongodb and mongoose).
OK, how I had to save the record in the reference too, I adopted this approach:
RecipeSchema.pre('remove', function(next) {
Complaint.remove({ "Recipe" : this._id }).exec();
next();
});
ComplaintSchema.pre('remove', function(next) {
Recipe.findById(this.Recipe).exec((error, item) => {
var index = item.Complaints.indexOf(item.Complaints.find(e => e._id == this._id));
item.Complaints.splice(index, 1);
item.save(() => { next(); });
});
});
ComplaintSchema.pre('save', function(next) {
Recipe.findById(this.Recipe).exec((error, item) => {
item.Complaints.push(this);
item.save(() => { next(); });
});
});
using this trigger/event available on the mongo schemas.
That worked perfectly!

Object.assign() Issues on Mongoose SubDocument Schema

So when I use Object.assign, (ex. Object.assign({foo:bar1},{foo:bar2}) on a particular Mongoose Subdocument Schema, the foo:bar2 obj won't overwrite the foo:bar1 obj.
In my app I have an Account Schema with two sub-document schemas, Projects & Properties. It's in the Project sub document schema that I encounter the issue.
Here are my Models:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ProjectSchema = new Schema({
_id: String,
name: String,
}, { strict: false })
var PropertySchema = new Schema({
_id: String,
slug: String,
name: String,
type: String,
placeholder: String,
order: Number
}, { strict: false })
var AccountSchema = new Schema({
_id: String,
name: String,
slug: String,
email: String,
properties: [PropertySchema],
projects: [ProjectSchema],
}, { strict: false })
module.exports = mongoose.model('Account', AccountSchema);
Here is a snippet of my Middleware(I think that's what it's called, please correct me if I am wrong). This is where I do the Object.assign to overwrite the particular projects' properties. If it helps I can post all the routes.
router.route('/accounts/:account_id/projects/:project_id')
.get(function(req, res) {
Project.findById(req.params.project_id, function(err, project){
if (err)
res.send(err);
res.json(project);
});
})
.delete(function(req, res){
Account.findById(req.params.account_id, function(err,account){
if (err)
res.send(err);
account.projects.id(req.params.project_id).remove();
account.save(function(err) {
if(err)
res.send(err);
res.json({message: 'Project Deleted'});
});
})
})
.put(function(req, res){
Account.findById(req.params.account_id, function(err,account){
if (err)
res.send(err);
Object.assign(account.projects.id(req.params.project_id), req.body);
account.save(function(err) {
if(err)
res.send(err);
res.json({message: 'Project Updated'});
});
})
});
// ----------------------------------------------------
router.route('/accounts/:account_id/properties/:property_id')
.get(function(req, res) {
Property.findById(req.params.property_id, function(err, property){
if(err)
res.send(err);
res.json(property);
});
})
.delete(function(req, res){
Account.findById(req.params.account_id, function(err, account){
if (err)
res.send(err);
account.properties.id(req.params.property_id).remove();
account.save(function(err){
if(err)
res.send(err);
res.json({ message: 'Successfully Deleted' });
})
})
})
.put(function(req, res){
Account.findById(req.params.account_id, function(err, account) {
if (err)
res.send(err);
Object.assign(account.properties.id(req.params.property_id), req.body);
account.save(function(err) {
if(err)
res.send(err);
res.json({message: 'Property Updated'});
})
})
});
So it's the Put Method that is giving me the issue, I can Get, Post, Delete with no issues, but the Put part for Projects is where I encounter this Object.assign issue. Funny thing is that everything works perfectly for the Property Schema Put Method, and it is basically the exact same as the Project one.
If I console.log some of the values in the Project's Put Method I get the following:
console.log(account.projects.id(req.params.project_id));
//original value logs { _id: '1486609836741', foo: 'bar' }
console.log(req.body);
//updated value logs { foo: 'barred', _id: '1486609836741' }
console.log(Object.assign(account.projects.id(req.params.project_id), req.body));
//logs the original value { _id: '1486609836741', foo: 'bar' }
So when I log the updated and original values they have equal keys, shouldn't the Object.assign work? Is the original Obj more complex then what the console.log displays, and maybe the original and updated don't have equal keys?
I am kinda stumped, any help would be greatly appreciated. Let me know if I need to post more of my code. Thanks.
Object.assign(account.projects.id(req.params.project_id), req.body);
Here, you are trying to assign to an object that is result of MongooseDocumentArray.id method call on account.projects array. Which will affect just a copy of document which is returned by function, and won't affect the original array of subdocuments.
I am new to Mongoose, but I'll suggest you trying to work with account.projects as with MongooseArray:
var project = account.projects.id( req.params.project_id ),
index = account.projects.indexOf( project );
Object.assign( account.projects[ index ], req.body);

Resources