Populating the cart doesnt work (mongoose) - node.js

I have been trying to populate cart products in user's cart. Below is my code.
const express = require('express')
const mongoose = require('mongoose')
const bodyParser = require('body-parser')
const app = express()
app.use(bodyParser.urlencoded({extended:false}))
const Schema = mongoose.Schema;
var userSchema = new Schema({
userName : {
type : String,
default : 'UserName'
},
cart : [ { type : mongoose.Schema.Types.ObjectId , ref : 'Cart' } ]
})
var cartSchema = new Schema({
productNameofUser : {
type : String,
default : 'Product'
}
})
var UserModel = mongoose.model('User' , userSchema)
var CartModel = mongoose.model('Cart' , cartSchema)
app.get('/users',(req,res)=>{
UserModel.find().populate('cart').exec((err,result)=>{
res.send(result)
})
})
app.post('/createUser',(req,res)=>{
let newUser = new UserModel()
newUser.save((err,result)=>{
console.log(result)
res.send(result)
})
})
app.get('/products',(req,res)=>{
CartModel.find((err,result)=>{
res.send(result)
})
})
app.post('/createProduct',(req,res)=>{
let newProduct = new CartModel()
newProduct.save((err,result)=>{
res.send(result)
})
})
app.listen(3000,()=>{
console.log('running')
mongoose.connect('mongodb://127.0.0.1:27017/populate' , { useNewUrlParser : true })
})
what I am trying to do is, There is a carts collection and there is another collection of users. Every user has a cart which i am trying to populate from the cart collections.
If you want to test the code, first create the user using the post link 'http://localhost:3000/createUser/' via postman and the create cart Products using 'http://localhost:3000/createProduct/' via postman. Then whenever i tried to fetch the users 'http://localhost:3000/users/' , the cart array stays empty no matter what i try.
Please figure where i am going wrong

Update your Schema defination as:
const Schema = mongoose.Schema;
var userSchema = new Schema({
userName : {
type : String,
default : 'UserName'
},
cart : [ { type : Schema .ObjectId , ref : 'Cart' } ]
})
And try this again:
app.get('/users',(req,res)=>{
UserModel.find().populate('cart').exec((err,result)=>{
res.send(result)
})
})
Let me know, if this works now.

Related

Value not incrementing in mongoose when creating a new object

Here is my code, I want to increment the total no of counts as soon as any user gives the rating. But the $inc command is not running and result is showing the default value which I set zero.
The given is my Schema.
const mongoose = require('mongoose');
const schema = mongoose.Schema;
let Rating = new schema({
user_id:{
type:mongoose.Types.ObjectId
},
stars:{
type:Number
},
ratingCount:{
type:Number,
default:0
}
})
const rating = mongoose.model('Rating', Rating);
module.exports = rating;
This is the function where I want to increment the value.
const express = require('express');
const Router = express.Router();
let Rating = require('../model/rating');
Router.route('/add/:userid').post((req,res)=>{
new Rating({
user_id: req.params.userid,
$inc: {ratingCount:1},
stars: req.body.stars
})
.save()
.then(rating=>res.send(rating))
.catch(err=>console.log(err));
});
module.exports = Router;
Result showing default value of ratingCount.
You need not to use .save() instead you can simply use .findOneAndUpdate() with option { new: true } to return updated document, if it doesn't find any matching document .findOneAndUpdate() will return null.
Code :
const express = require("express");
const Router = express.Router();
let Rating = require("../model/rating");
Router.route("/add/:userid").post((req, res) => {
Rating.findOneAndUpdate(
{ user_id: req.params.userid },
{ $inc: { ratingCount: 1 }, stars: req.body.stars },
{ new: true }
)
.then((rating) => res.send(rating))
.catch((err) => console.log(err));
});
module.exports = Router;
Usually .save() will track changes to document which is returned from find call. Otherwise if it's not the mongoose document returned from .find() call if it's the mongoose object which you're forming like what you're doing now then if it finds _id in object it will update the matching doc else if no matching doc exists with _id or no _id present in request it will insert the new document.

How to solve Mongoose Error on Validation

I am building an API that allows the user to log certain data into the database(MongoDB) The problem is I keep getting the following errors:
UnhandledPromiseRejectionWarning: ValidationError: item validation failed: productName: Path `productName` is required.
here is my schema :
const mongoose= require('mongoose');
const Schema = mongoose.Schema;
//create Schema
const ItemSchema = new Schema({
productName : {
type : String,
required:true
} ,
description : {
type :String,
default:true
},
supplier : {
type :String,
default:true
},
price : {
type :Number,
default:true
},
date : {
type :Date,
default:Date.now
}
});
module.exports=Inventory=mongoose.model('item',ItemSchema,'inventory');
Here is the submit post route:
const express= require('express');
const router = express.Router();
//Items model
const Inventory = require('../../../models/Inventory');
router.post('/',(req,res)=>{
const newInventory= new Inventory({
productName:req.body.productName,
description:req.body.description,
supplier:req.body.supplier,
price:req.body.price,
});
newInventory.save().then(item=>res.json(item))
});
I can't figure out why it's throwing a validation Error!
This was the step I took to resolve the problem
first, i checked what i was getting from my req.body
const express= require('express');
const router = express.Router();
//Items model
const Inventory = require('../../../models/Inventory');
console.log(req.body) //checking for content of req.body
router.post('/',(req,res)=>{
const newInventory= new Inventory({
productName:req.body.productName,
description:req.body.description,
supplier:req.body.supplier,
price:req.body.price,
});
newInventory.save().then(item=>res.json(item))
});
I got an empty object { }, this means I wasn't getting any request in the first place. Testing with Postman, I changed the option from "form data" to :
x-www-form-urlencoded
this filled my req.body with data and the error disappeared !

Filter moongose results by reference field using express

I need filter the products of a collection by category id which is a reference field.
product.js
const restful = require('node-restful')
const mongoose = restful.mongoose
const productSchema = new mongoose.Schema({
name: { type: String, required: true },
category: {type: mongoose.Schema.Types.ObjectId, ref: 'CategoryProduct'}
})
productSchema.pre('find', function () {
this.find().populate('category')
})
module.exports = restful.model('product', productSchema)
routes.js
const express = require('express')
const auth = require('./auth')
module.exports = function (server) {
const protectedApi = express.Router()
server.use('/api', protectedApi)
const Product = require('../api/product/productService')
Product.register(protectedApi, '/products')
}
If I run this on Postman, http://localhost:3003/api/products/?name__regex=/test/i, I can get all products which contains 'test' on name.
So I try get all products by a specific category doing this, http://localhost:3003/api/products/?category=5af3ac4372edc6000468d766.
But as the category is an objectID, I receive this error:
{
"message": "Cast to ObjectId failed for value \"5\" at path \"category\" for model \"SimpleProduct\"",
"name": "CastError",
"stringValue": "\"5\"",
"kind": "ObjectId",
"value": 5,
"path": "category"
}
How do I filter the products by category? I do not know how to treat this parameter correctly and pass to mongoose
Here is my CategoryProduct.js file
const restful = require('node-restful')
const mongoose = restful.mongoose
const categorySchema = new mongoose.Schema({
name: {type: String, required: 'O campo Categoria é obrigatório'},
status: {type: Number, required: true},
updated_at: {type: Date}
})
module.exports = restful.model('CategoryProduct', categorySchema)
you would have to do the following in your route:
const mongoose = require('mongoose');
router.get('/', (req, res, next) => {
const category = req.query.category; // assign the query param for use
// mongoose query now
Product.find({category: mongoose.Types.ObjectId(category)}, (err, result) => {
if (err) {console.log(err)};
if (result) {
res.json(result);
}
});
});
This is just a basic example. Since you are using node-restful you might have to adjust the code but the main idea here is that you require the mongoose module using
const mongoose = require('mongoose')
then pass your category query param to it to convert the string to objectID using:
mongoose.Types.ObjectID(YOUR_CATEGORY_PARAM_HERE)
You can do this anywhere, in the your routes.js or in your express.js, just have to have the string you want to convert :)
hope that helps :).

Mongoose - Can't push a subdocument into an array in parent Document

I am trying to push a subdocument(ApplicationSchema) into my Job schema. But it doesn't seem to work.
Following is my Job Schema :
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
var ApplicationSchema = require('./Application');
const Job = new Schema({
skills : {
type : Array
},
active : {
type : Boolean,
default : false
},
applications: [ApplicationSchema],
userId : {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
},{timestamps : true});
export default mongoose.model("Job", Job)
This is subdocument(ApplicationSchema). I have 5 more subdocuments in this schema.
I am pushing an object with a key-value pair of talentId and its value. But it doesn't work.
I get a new object in the array but the object I'm trying to push is not pushed.
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
var notesSchema = require('./notesSchema');
var documentSchema = require('./documentSchema');
var assessmentSchema = require('./assessmentSchema');
var interviewScheduleSchema = require('./interviewScheduleSchema');
var referenceSchema = require('./referenceSchema')
const ApplicationSchema = new Schema({
talentId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Talent'
},
applicationType: {
type: Number
}
notes: [notesSchema],
documents: [documentSchema],
assessment: [assessmentSchema],
interviewSchedule: [interviewScheduleSchema],
references: [referenceSchema]
},{
timestamps: true
});
export default ApplicationSchema;
Following is my code in the API endpoint
.post((req, res, next) => {
Job.findById(req.params.jobId)
.then((job) => {
if (job != null) {
job.applications.push(req.body);
job.save()
.then((job) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(job);
})
}
else {
err = new Error('Job ' + req.params.jobId + 'not found')
err.status = 404;
return next(err);
}
}, (err) => next(err))
.catch((err) => next(err));
})
req.body contains following object
{ talentId: '5a813e1eb936ab308c4cae51' }
If you already have the id of the job document then you can push application object direct by doing the following:
Job.update(
{ _id: req.params.jobId },
{ $push: { applications: req.body} },
callback
);
or you can use promise to handle this. and if you are only saving id of the application then you may want to change your job schema to store Id of the applications instead of whole application schema.
Please read the documentation carefully as this is very basic update query.
You have,
talentId: {type: mongoose.Schema.Types.ObjectId,
ref: 'Talent'}
But your req.body contains:
{ talentId: '5a813e1eb936ab308c4cae51' }
It should be:
{ talentId: mongoose.Types.ObjectId('5a813e1eb936ab308c4cae51') }
Turns out there was nothing wrong with code.
I was using import and export default syntax which didn't seem work well with this.
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
and
export default ApplicationSchema;
I replaced them with Common JS syntax and everything worked fine.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
and
module.exports = ApplicationSchema;
I did this for Job document file and every subdocument file and the code worked.

One to Many Relationship MongoDb Using Mongoose

I am creating a relationship between a User and Address. User can have multiple Address. Here is my schema:
userSchema.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const Address = require('./addressSchema')
let userSchema = mongoose.Schema({
name :String,
age : Number,
cohort :String,
addresses : [{type : Schema.Types.ObjectId, ref : 'Address'}]
})
let User = mongoose.model('User',userSchema)
module.exports = User
addressSchema.js
const mongoose = require('mongoose')
let addressSchema = mongoose.Schema({
city : String,
state :String
})
let Address = mongoose.model('Address',addressSchema)
module.exports = Address
Adding New User and Address (app.js)
let user = new User({name : 'Mary', age : 36, cohort : 2019})
let address = new Address({ city : 'Houston', state : 'TX'})
user.addresses.push(address)
user.save(function(error,newUser){
console.log(newUser)
})
Fetching the users and their addresses
// fetch all users
User.find(function(error,users){
users.forEach((user) => {
console.log('addresses')
user.addresses.forEach((address) => {
console.log(address.city) // prints undefined
})
})
})
Any ideas what I am doing wrong?
It depends on what you are trying to accomplish: storing the addresses as embedded documents in user OR storing references to address documents in user. The example code above has blended both approaches which, as you have noticed, does not work.
Embedded:
Combine the schemas:
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const addressSchema = Schema({
city : String,
state :String
})
const userSchema = Schema({
name :String,
age : Number,
cohort :String,
addresses : [addressSchema]
});
const User = mongoose.model('User',userSchema);
And the rest of the code can remain the same.
References:
The existing schema and model declarations remain the same.
Then when the data is stored, the address also needs to be stored:
const user = new User({name : 'Mary', age : 36, cohort : 2019})
const address = new Address({ city : 'Houston', state : 'TX'})
user.addresses.push(address)
Promise.all([
user.save(),
address.save()
]).then(([newUser, newAddress]) => {
console.log({newUser, newAddress});
});
And finally when fetching the document, if the address is meant to be included then it needs to be populated:
User.find().populate('addresses').exec().then((users) => {
users.forEach((user) => {
user.addresses.forEach((address) => {
console.log({user, address});
});
});
});

Resources