How to add data inside nested array in mongodb - node.js

I am using mongoose for database functionalities in my nodejs project.Below is my model.
Here is the POST request:
In MongoDb data is saving like this :
Here owers array is empty.
expense.js
const mongoose = require('mongoose');
const ExpenseSchema = new mongoose.Schema({
userid:{
type: String,
required: true
},
owers:[{
owerid:{
type: String
},
amt:{
type: Number
}
}],
name:{
type: String,
required: true
},
amount:{
type: Number,
require: true
}
});
const expense = mongoose.model('expense',ExpenseSchema);
module.exports = expense;
Whenever I am trying to insert something array is showing empty.Below is my code:
addExpense.js
const expense = require('../models/expense.js');
const addExpense = async (req,res) => {
const {name,amount,owerid,amt} = req.body;
console.log(name + " " + owerid);
const {userid} = req.params;
const expens = new expense({userid,name,amount});
try{
const data = await expens.save();
expens.owers.push({"owerid":owerid,"amt":amt});
res.send({"id":data._id});
}
catch(error){
res.send(error);
}
};
module.exports = {addExpense};
Someone let me know what I am doing wrong.

Try This
const {name,amount,owers} = req.body;
console.log(name + " " + owerid);
const {userid} = req.params;
const expens = new expense({userid,name,amount});
try{
const data = await expens.save();
//After you can push multiple data like that
JSON.parse(owers).map((value) => {
data.owers.push({
owerid: value.owerid,
amt: value.amt
})
})
data.save()
res.send({"id":data._id});
}
catch(error){
res.send(error);
}

Related

How should I change the value of the field before saving it to database?

I am new to Node.js and I'm trying to perform CRUD operation right now. I have this function to save data to the mongoDB database but the thing is I'm trying to change the value of one particular field before saving it to database. The problem is that my data is getting saved first and then the calculations are being performed. Here is my post function:
router.post('/', async(req, res) => {
const reservation = new Reservation({
guestID: mongoose.Types.ObjectId(req.body.guestID),
roomID: mongoose.Types.ObjectId(req.body.roomID),
checkIn: req.body.checkIn,
checkOut: req.body.checkOut,
numberOfAdults: req.body.numberOfAdults,
totalCost: req.body.totalCost,
numberOfChildren: req.body.numberOfChildren
})
try
{
const reservationRecord = await reservation.save()
res.json(reservationRecord)
}
catch(err)
{
console.log(err)
res.send("Error")
}
})
And here is the Schema
const mongoose = require('mongoose')
const axios = require('axios')
const reservationSchema = new mongoose.Schema({
guestID: {
type: mongoose.SchemaTypes.ObjectId,
required: true
},
roomID: {
type: mongoose.SchemaTypes.ObjectId,
required: true
},
checkIn: {
type: Date,
required: true
},
checkOut: {
type: Date,
required: true
},
numberOfAdults: {
type: Number,
required: true
},
numberOfChildren: {
type: Number,
required: true
},
totalCost: {
type: Number,
required: false,
default: 0
}
})
reservationSchema.pre('save', function(next){
var date1 = new Date(this.checkIn);
var date2 = new Date(this.checkOut);
var diff = Math.abs(date1.getTime() - date2.getTime());
var diffDays = Math.ceil(diff / (1000 * 3600 * 24));
console.log(diffDays)
var roomCost
var totalRoomCost
axios.get("http://localhost:5555/rooms/" + this.roomID).then((response) => {
console.log(response)
roomCost = response.data.cost;
console.log("room cost is " + roomCost)
totalRoomCost = (this.numberOfAdults + this.numberOfChildren) * response.data.cost * diffDays
this.totalCost = totalRoomCost
})
//this.totalCost = (this.numberOfAdults + this.numberOfChildren) * roomCost * diffDays
console.log(this.totalCost)
next()
})
const Reservation = mongoose.model('reservation', reservationSchema)
module.exports = Reservation
I want to change the value of totalCost before saving it to database. Can somebody let me know what the problem is with the code?
Thank you!
You should just handle the calculations in your POST method, before your create your new Reservation instance:
router.post('/', async (req, res) => {
try {
const {
numberOfChildren,
numberOfAdults,
roomID,
checkIn,
checkOut,
} = req.body;
var date1 = new Date(checkIn);
var date2 = new Date(checkOut);
var diff = Math.abs(date1.getTime() - date2.getTime());
var diffDays = Math.ceil(diff / (1000 * 3600 * 24));
const room = await Room.findById(roomID)
const newTotalCost = (numberOfAdults + numberOfChildren) * room.cost * diffDays;
const reservation = new Reservation({
...req.body,
totalCost: newTotalCost,
});
const reservationRecord = await reservation.save();
res.json(reservationRecord);
} catch (err) {
console.log(err);
res.send('Error');
}
});
Of course, the reservationSchema.pre('save') function is unecessary in this case.

How do I reference documents from other collection in express

I have 2 collections here >>course & author
I need to prepare my course schema in such a way that it references the author and at the post request I only need to put the id.I am using #joi13 This is what I have done so far.
course schema
const mongoose = require('mongoose')
const Joi = require('joi')
Joi.objectId= require('joi-objectid')(Joi)
// schema
const courseSchema = new mongoose.Schema({
...
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Author'
}
})
// the model
const Course = mongoose.model('Courses', courseSchema)
// validation
const courseValidation = (course) => {
const schema = {
...
authorId: Joi.objectId().required()
}
return Joi.validate(course, schema)
}
the course router
const {Course, validate} = require('../models/course')
const express = require('express')
const router = express.Router()
const {Author} = require('../models/author')
// post
router.post('/', async (req, res) => {
const {error} = validate(req.body)
if (error) return res.status(400).send(error.details[0].message)
const title = await Course.findOne({title : req.body.title})
if (title) return res.status(400).send('That user exists')
const author = await Author.find()
if (!author) return res.status(404).send('No such Author')
let course = new Course({
...
author: {
_id: author._id,
username: author.username
}
})
try {
course = await course.save()
res.send(course)
}
catch(er){
console.log(er)
}
})
The error
At line, const author = await Author.find() will return array of authors
while creating course at following lines of you are using author._id which will be undefined, So you have to find a specific Author using findOne (return a single author as object) or you have to use an indexed element of an author like author[0]._id
let course = new Course({
...
author: {
_id: author._id,
username: author.username
}
})

HOW TO FIX Mongoose 5.11.8 model.find() ERROR Operation `thanks-leaderboards.find()` buffering timed out after 10000ms

How to solve model.find() function produces "buffering timed out after ... ms"? I'm using mongoose v 5.11.8, npm v6.14.8 and mongodb v3.6.3
Here's the code.
thanks-leaderboard.js
const thanksLeaderboardSchema = require('../../schemas/thanks-leaderboard-schema.js')
const thanksSchema = require('../../schemas/thanks-schema.js')
const fetchTopMembers = async (guildId) => {
let text = ''
const results = await thanksSchema
.find({
guildId,
})
.sort({
received: -1,
})
.limit(10)
for (let counter = 0; counter < results.length; ++counter) {
const { userId, received = 0 } = results[counter]
text += `#${counter + 1} <#${userId}> with ${received} thanks\n`
}
text += '\nThis is updated every minute'
return text
}
const updateLeaderboard = async (client) => {
const results = await thanksLeaderboardSchema.find({}).where('channelId')
for (const result of results) {
const { channelId, _id: guildId } = result
const guild = client.guilds.cache.get(guildId)
if (guild) {
const channel = guild.channels.cache.get(channelId)
if (channel) {
const messages = await channel.messages.fetch()
const firstMessage = messages.first()
const topMembers = await fetchTopMembers(guildId)
if (firstMessage) {
firstMessage.edit(topMembers)
} else {
channel.send(topMembers)
}
}
}
}
setTimeout(() => {
updateLeaderboard(client)
}, 1000 * 60)
}
module.exports = async (client) => {
updateLeaderboard(client)
}
set-leaderboard.js
const leaderBoardSchema = require('../../schemas/thanks-leaderboard-schema.js')
module.exports = {
commands: 'setleaderboard',
requiredRoles: ['Administrator'],
description: 'Erstelle ein Leaderboard für die vergebenen Danksagungen',
callback: async (message) => {
const { guild, channel} = message
const guildId = guild.id
const channelId = channel.id
await leaderBoardSchema.findOneAndUpdate({
_id: guildId,
channelId,
},
{
_id: guildId,
channelId,
},
{
upsert: true,
})
message.reply('Leaderboard wurde erstellt!').then((message) => {
message.delete({
timeout: 1000 * 5,
})
})
message.delete()
}
}
thanks-leaderboard-schema.js
const mongoose = require('mongoose')
const reqString = {
type: String,
required: true,
}
const thanksLeaderboardSchema = mongoose.Schema({
// Guild ID
_id: reqString,
channelId: reqString,
})
module.exports = mongoose.model('thanks-leaderboards', thanksLeaderboardSchema, 'thanks-leaderboards')
thanks-schema.js
const mongoose = require('mongoose')
const reqString = {
type: String,
required: true,
}
const thanksSchema = mongoose.Schema({
userId: reqString,
guildId: reqString,
received: {
type: Number,
default: 0,
},
lastGave: Date,
})
module.exports = mongoose.model(
'thanks',
thanksSchema,
'thanks'
)
I tried increasing the bufferTimeoutMS or disabling the bufferCommands but still it won't work. This Code is supposed to readout the database every 60 seconds but the timeout happens after 10 seconds... can't figure out how to fix this error. I've already tried to delete the node_modules folders for mongoose and mongodb and reinstall them via npm but that didn't work as I get this error again.

Mongoose set empty array when update model

I have a problem with mongoose. I use MEAN stack.
I have an House Schema with some fields. When I update the house (with save method) mongoose update all fields but set an array in nested object empty. Why?
HOUSE SCHEMA
const mongoose = require('mongoose');
const posSchema = require('./pos');
const reviewSchema = require('./reviews');
const roomSchema = require('./rooms');
const contactSchema = require('./contacts');
const nearSchema = require('./nears');
const houseSchema = new mongoose.Schema({
title: { type: String, required: true },
description: { type: String, required: true },
shared: {
description: { type: String, required: true },
photos: { type: [String], required: true }
},
// OTHER FIELDS
}, { timestamps: true });
mongoose.model('House', houseSchema);
UPDATE FUNCTION
House.findById(body.house._id, "-__v", async (err, house) => {
if (err) { return res.status(400).json(err); }
else if (!house) { return res.status(400); }
house.title = body.house.title;
house.totalSize = parseInt(body.house.totalSize.toString());
house.bathrooms = parseInt(body.house.bathrooms.toString());
house.totalBeds = parseInt(body.house.totalBeds.toString());
house.description = body.house.description;
house.totalFreeBeds = parseInt(body.house.totalFreeBeds.toString());
house.minPrice = parseFloat(body.house.minPrice.toString()).toFixed(2);
house.type = body.house.type;
house.level = body.house.level;
house.top_floor = body.house.top_floor;
house.rooms = body.house.rooms;
house.checkboxes = body.house.checkboxes;
house.contacts = body.house.contacts;
house.pos = body.house.pos;
house.save(err => {
if (err) { console.log(err); return res.status(400).json(err); }
return res.status(200).json({ status: 200, remove: remove });
});
});
Before updating house.shared.photos is ["foo", "bar"]
After is [].
Why?
You are not setting the house.shared anywhere.
Try adding house.shared = body.house.shared before save call.

NodeJs Express API, trying to adding data/updating data to MongoDB but getting "Cannot read property '_id' of undefined"

I am trying to add a new collection, using the same ObjectId from the my users collection that was already created. But when I run the API, I get the following error Cannot read property '_id' of undefined
index.js
const express = require('express');
const authRoutes = require('./auth.routes');
const profileRoutes = require('./profile.routes');
const router = express.Router();
router.use('/auth', authRoutes);
router.use('/profile', profileRoutes);
module.exports = router;
profile.routes.js
const express = require('express');
const profileCtrl = require('../controllers/profile.controller');
const router = express.Router();
router
.route('/')
.post(profileCtrl.create)
.put(profileCtrl.update)
.get(profileCtrl.read)
.delete(profileCtrl.remove);
module.exports = router;
BaseCrudController.js
class BaseCrudController {
constructor(dataService, varName) {
if (!dataService) {
throw new Error('Data service not found', 500);
}
this.varName = varName;
this.dataService = dataService;
this.create = this.create.bind(this);
this.update = this.update.bind(this);
}
create(req, res, next) {
return this.dataService
.create(req.user, req.body)
.then((item) => res.json(item))
.catch(next);
}
update(req, res, next) {
return this.dataService
.update(req.user, req[this.varName], req.body)
.then((item) => res.json(item))
.catch(next);
}
BaseCrudService.js
const _ = require('lodash');
const mongoose = require('mongoose');
const APIError = require('../utils/api-error');
const BaseService = require('./BaseService');
class BaseCrudService extends BaseService {
constructor(
modelName,
safeFields = [],
adminFields = [],
userIdField = null,
populatedFields = [],
listPoluateField = ''
) {
super();
this.modelName = modelName;
this.safeFields = [...safeFields];
this.fields = [...safeFields];
this.adminFields = [...adminFields];
this.userIdField = userIdField;
this.populatedFields = [...populatedFields];
this.listPoluateField = listPoluateField;
this.model = mongoose.model(this.modelName);
this.create = this.create.bind(this);
this.update = this.update.bind(this);
}
_getFiedlNames(user) {
//maybe checking roles later
return [...this.safeFields];
}
create(user, data, extraData = {}) {
const Model = this.model;
const createData = {};
const fields = this._getFiedlNames(user);
if (this.userIdField) {
createData[this.userIdField] = user._id;
}
const item = new Model(
Object.assign(createData, _.pick(data, fields), extraData)
);
return item.save();
}
update(user, item, data) {
const fields = this._getFiedlNames(user);
const updateData = _.pick(data, fields);
Object.assign(item, updateData);
return item.save();
}
profile.model.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
const profileSchema = new Schema({
user: { type: Schema.ObjectId, ref: 'User', required: true },
contactEmail: {
type: String,
required: true,
},
isEnabled: {
type: Boolean,
default: false,
},
about: {
type: String,
default: '',
},
portfolioUrl: {
type: String,
default: '',
},
jobTitle: {
type: String,
default: '',
},
resumeUrl: {
type: String,
default: '',
},
});
module.exports = mongoose.model('Profile', profileSchema);
Then when I try to test this in Postman, I get the following stack "TypeError: Cannot read property '_id' of undefined\n at ProfileService.create (/Users/tj/aydensoft/upwork-ABDS/portfolios/portfolios/services/BaseCrudService.js:46:43)\n at ProfileController.create (/Users/tj/aydensoft/upwork-ABDS/portfolios/portfolios/controllers/BaseCrudContoller.js:20:8)\n
Also the users collection automatically gets the _id:ObjectId("someNumber") when a user is added.
I tried many different ways but it ends up adding a totally different _id:ObjectId("someNumber") instead of the one matching _id:ObjectId("someNumber") in the users collection.

Resources