Mongoose post update middleware not working - node.js

I am use "mongoose": "^4.1.2". I have try to update a matchRate field when after a document being updated. But it doesn't work either not throw an any errors.
Here is code:
list.model.js
'use strict';
var mongoose = require('bluebird').promisifyAll(require('mongoose'));
import { Schema } from 'mongoose';
var ListSchema = new Schema({
name: { type: String, required: true },
user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
emails: [],
emailColRef: String,
matchCount: Number,
totalCount: Number,
matchRate: Number,
state: {
type: String,
enum: ['pending', 'complete', 'invalid']
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
default: {
type: Boolean,
default: false
}
});
ListSchema
.virtual('count')
.get(() => this.emails.length);
ListSchema
.post('update', function() {
// this.update({},{ $set: { matchRate: this.matchCount / this.totalCount } });//Not working
//////-------------OR---------------//////
// this.matchRate=this.matchCount / this.totalCount;//Not working
console.log(this.matchCount);//undefined
console.log(this.totalCount);//undefined
console.log(this.matchRate);//undefined
});
export default mongoose.model('List', ListSchema);
list.controller.js
.....
.....
.....
var newList = {};
newList.name = name;
newList.emails = emails;
newList.emailColRef = emailColRef;
newList.state = status;
newList.matchCount = matchCount;
newList.totalCount = totalCount;
var query = { name: req.body.name };
List.update(query, newList, function(err, doc) {
// index(req, res);
if (err) {
console.log("Error in list update ", err)
return;
}
fs.unlink(req.file.path, function(err) {
if (err) {
console.log("Error in removing file", err)
return;
}
});
console.log('Update list with match status');
});

Related

How to Calculate and return a total cart items in Nodejs and Express

I've been going back and forth on this code for sometime now and I'm trying to have a totalQty value in the cart object that returns total number of items in the cart and I want to use that value in the views of course right next to the cart icon in the navigation. Here is my code for the user model and routes:
User model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
role: {
type: String,
default: 'BASIC'
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
address: {
type: String
},
apartment: {
type: String
},
country: {
type: String
},
state: {
type: String
},
city: {
type: String
},
zip: {
type: String
},
phone: {
type: String
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
resetToken: String,
resetTokenExpiration: Date,
cart: {
items: [
{
productId: {
type: Schema.Types.ObjectId,
ref: 'Product',
required: true
},
quantity: { type: Number, required: true }
},
],
totalQty: {
type: Number,
default: 0
}
}
}, { timestamps: true });
userSchema.methods.addToCart = function (product) {
const cartProductIndex = this.cart.items.findIndex(cp => {
return cp.productId.toString() === product._id.toString();
});
let newQuantity = 1;
// let newTotalQty = 1;
const updatedCartItems = [...this.cart.items];
if (cartProductIndex >= 0) {
newQuantity = this.cart.items[cartProductIndex].quantity + 1;
updatedCartItems[cartProductIndex].quantity = newQuantity;
newTotalQty = this.cart.totalQty + 1;
updatedTotalQty = newTotalQty;
} else {
updatedCartItems.push({
productId: product._id,
quantity: newQuantity
});
}
const updatedCart = {
items: updatedCartItems,
totalQty: updatedTotalQty
};
this.cart = updatedCart;
return this.save();
};
userSchema.methods.removeFromCart = function (productId) {
const updatedCartItems = this.cart.items.filter(item => {
return item.productId.toString() !== productId.toString();
});
this.cart.items = updatedCartItems;
return this.save();
};
userSchema.methods.clearCart = function () {
this.cart = { items: [] };
return this.save();
};
module.exports = mongoose.model('User', userSchema);
User routes:
exports.getCart = (req, res, next) => {
// populate req user
req.user
.populate('cart.items.productId')
.execPopulate()
.then(user => {
const products = user.cart.items;
// render cart view
res.render('shop/cart', {
path: '/cart',
pageTitle: 'Cart - Hashing365.com',
products: products
});
})
.catch(err => {
const error = new Error(err);
error.httpStatusCode = 500;
return next(error);
});
};
exports.postCart = (req, res, next) => {
// extract prod ID
const prodId = req.body.productId;
// run DB find with prod ID
Product.findById(prodId)
.then(product => {
// return true && add to cart
return req.user.addToCart(product);
})
.then(result => {
// re-render same page
res.redirect('back');
})
.catch(err => {
const error = new Error(err);
error.httpStatusCode = 500;
return next(error);
});
};
Would really appreciate if someone could help me with a way to do that. Thanks!
You can look into Array reducer function. It should look like this
cart.totalQty = cart.items.reduce((sum, item)=>{
return sum + item.quantity;
},0);

Cast to ObjectId failed for value at path for model error

This is my Profile Schema:
const mongoose = require('mongoose');
const ProfileSchema = new mongoose.Schema({
user: {
// Special field type because
// it will be associated to different user
type: mongoose.Schema.Types.ObjectId,
ref: 'user',
},
company: {
type: String,
},
website: {
type: String,
},
location: {
type: String,
},
status: {
type: String,
required: true,
},
skills: {
type: [String],
required: true,
},
bio: {
type: String,
},
githubusername: {
type: String,
},
experience: [
{
title: {
type: String,
required: true,
},
company: {
type: String,
required: true,
},
location: {
type: String,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
education: [
{
school: {
type: String,
required: true,
},
degree: {
type: String,
required: true,
},
fieldofstudy: {
type: String,
required: true,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
social: {
youtube: {
type: String,
},
twitter: {
type: String,
},
facebook: {
type: String,
},
linkedin: {
type: String,
},
instagram: {
type: String,
},
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = Profile = mongoose.model('profile', ProfileSchema);
This is my view api. It doesn't work. it only return Cast to ObjectId failed for value { 'experience._id': '5edcb6933c0bb75b3c90a263' } at path _id for model profile
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
const exp = await Profile.findById({
'experience._id': req.params.viewexp_id,
});
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
How can I fix this? I tried looking at the stackoverflow of the same errors. still it doesn't seem to work.
and this is what I am trying to hit
The problem is that you have to convert your string _id to mongoose object id using this function mongoose.Types.ObjectId and my suggestion is to use findOne function instead of findById,
var mongoose = require('mongoose');
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
let id = mongoose.Types.ObjectId(req.params.viewexp_id);
const exp = await Profile.findOne(
{ "experience._id": req.params.viewexp_id },
// This will show your sub record only and exclude parent _id
{ "experience.$": 1, "_id": 0 }
);
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
var mongoose = require('mongoose');
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
const exp = await Profile.findOne({
'experience._id': mongoose.Types.ObjectId(req.params.viewexp_id),
});
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
You are saving object id . but your param id is string. convert it in ObjectId. Please check my solution.
router.post(
"/",
[
auth,
[
check("status", "status is required").not().isEmpty(),
check("skills", "skills is required").not().isEmpty(),
],
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
company,
website,
location,
bio,
status,
githubuername,
skills,
youtube,
facebook,
twitter,
instagram,
linkedin,
} = req.body;
const profileFileds = {};
profileFileds.user = req.user.id;
if (company) profileFileds.company = company;
if (website) profileFileds.website = website;
if (location) profileFileds.location = location;
if (bio) profileFileds.bio = bio;
if (status) profileFileds.status = status;
if (githubuername) profileFileds.githubuername = githubuername;
if (skills) {
profileFileds.skills = skills.split(",").map((skill) => skill.trim());
}
//Build profile object
profileFileds.social = {};
if (youtube) profileFileds.social.youtube = youtube;
if (twitter) profileFileds.social.twitter = twitter;
if (facebook) profileFileds.social.facebook = facebook;
if (linkedin) profileFileds.social.linkedin = linkedin;
if (instagram) profileFileds.social.instagram = instagram;
try {
let profile = await Profile.findOne({ user: req.user.id });
if (profile) {
//update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFileds },
{ new: true }
);
return res.json(profile);
}
//Create profile
profile = new Profile(profileFileds);
await profile.save();
res.json(profile);
} catch (err) {
console.error(err.message);
res.status(500).send("server Error");
}
}
);

Can't get accessed to fields of instances in mongoose

There have already been some documents in the events collection, however when I try to log out the field "eventId", it shows me "unfefined".
Following is the code:
var EventSchema = mongoose.Schema({
eventId: { type: Number, required: true,unique: true },
name: { type: String, required: true },
loc: { type: ObjectId },
quota: { type: Number }
});
var Event = mongoose.model('Event', EventSchema);
app.get('/test',function(req,res){
Event.find(function(err,result){
if(err)
console.log("Not found");
console.log("This is" + result.eventId);
res.send(result);
});
});
Try:
var EventSchema = mongoose.Schema({
eventId: { type: Number, required: true,unique: true },
name: { type: String, required: true },
loc: { type: ObjectId },
quota: { type: Number }
});
var Event = mongoose.model('Event', EventSchema);
app.get('/test', async function(req,res){
const result = await Event.find();
console.log("This is the result: " + result);
res.send(result);
});
I think your problem is the callback is in the filter object position of the .find() method. The following may also work:
var EventSchema = mongoose.Schema({
eventId: { type: Number, required: true,unique: true },
name: { type: String, required: true },
loc: { type: ObjectId },
quota: { type: Number }
});
var Event = mongoose.model('Event', EventSchema);
app.get('/test',function(req,res){
Event.find({}, function(err,result){
if(err) console.log("Not found");
console.log("This is" + result.eventId);
res.send(result);
});
});

How to use mongoose to make changes in two different collections in one nodejs query

In this application, I am trying to update a field value, if it is successful then I want to save into a log collection, however, not all the data are saved in the log collection, I am not sure if I am doing it the right way, would appreciate if someone could help out.
here is the query :
// both models(Log & Inventory are imported)
router.get("/add_product/:id/:num/:quantity/:order", (req, res) => {
var id = req.params.id;
var quantity = req.params.quantity;
var order = req.params.order;
// console.log('id----', id);
var num_mod = req.params.num;
var modified_count = parseInt(num_mod) - parseInt(quantity);
console.log("num_mod----", num_mod);
Inventory.findByIdAndUpdate(id, { quantity: parseInt(num_mod) }, { new: true }, function(
err,
inventory
) {
if (err) {
console.log("err", err);
res.status(500).send(err);
} else {
console.log(inventory.name);
const newLog = new Log({
name: inventory.name,
description: inventory.description,
price: parseInt(inventory.price),
quantity: parseInt(inventory.quantity),
modified_quantity: parseInt(modified_count),
itemDest: order //this is not being saved
});
newLog.save(function(err, Log) {
if (err) {
console.log(err);
} else {
console.log("add log success");
res.send(inventory);
}
});
}
});
});
URL from front end :
// order is a string
here is the Log schema :
const mongoose = require("mongoose");
const LogSchema = new mongoose.Schema(
{
// _id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
description: { type: String, required: true },
price: { type: Number, required: true },
quantity: { type: Number, required: true },
modified_quantity: { type: Number, required: true },
supplier: String,
taxable: Boolean,
itemDest: String
},
{ timestamps: true }
);
// Create model from the schema
const Log = mongoose.model("Log", LogSchema);
// Export model
module.exports = Log;
and here is the inventory schema
const mongoose = require("mongoose");
//create Schema
const InventorySchema = new mongoose.Schema(
{
// _id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
description: { type: String, required: true },
price: { type: Number, required: true },
quantity: { type: Number, required: true },
supplier: String,
taxable: Boolean
},
{ timestamps: true }
);
// Create model from the schema
const Inventory = mongoose.model("Inventory", InventorySchema);
// Export model
module.exports = Inventory;
My issue is with this line "itemDest: order" in the query, I intend to save the value of "order" extracted from "req.params.order" into "itemDest" but it doesn't save.

Intersection of key values between 2 different collections in MongoDB

I have 2 collections: bookings and timeslots.
models/booking.js:
var mongoose = require ('../config/db');
var Schema = require('mongoose').Schema;
var ObjectId = Schema.ObjectId;
var bookingSchema = new Schema({
start: {
type: Number,
required: true
},
end: {
type: Number,
required: true
},
date: {
type: Date,
required: true,
default: Date.now
}
});
models/time_slot.js:
var mongoose = require ('../config/db');
var Schema = require('mongoose').Schema;
var ObjectId = Schema.ObjectId;
var timeSlotSchema = new Schema({
start: {
type: Number,
required: true
},
end: {
type: Number,
required: true
},
date: {
type: Number,
required: true,
default: Time.Today
},
enabled: {
type: Boolean,
required: true,
default: true,
},
pickup: {
type: Boolean,
required: true,
default: true,
}
});
Both have a field start in common. I would like to be able to get the entries from the collection timeslots in which the value of start has occurred in bookings.
I have tried:
controllers/time_slot.js:
var timeSlotModel = require('../models/time_slot').model;
var Booking = require('./booking');
Booking.getBookings({}, function(err, bookings) {
if (err) {
console.error(err);
} else {
timeSlotModel.find({start: bookings.start}, function(err, slots) {
if (err) {
console.error(err);
} else {
return next(null, slots);
}
}
}
But that doesn't work, unsurprisingly, and I get the error:
MongooseError: Cast to number failed for value "undefined" at path "start"
You can do it like this:
Booking.getBookings({}, function(err, bookings) {
if (err) {
console.error(err);
} else {
// build array with unique "start" values from bookings
var starts = bookings
.map(booking => booking.start)
.filter((val, i, self) => self.indexOf(val) === i)
// find by these start values
var query = {start: {$in: starts}}
timeSlotModel.find(query, function(err, slots) {
if (err) {
console.error(err);
} else {
return next(null, slots);
}
}
}

Resources