array data is not being sent to mongodb - node.js

I have this schema for my project but it is not pushing the data in mongo db
let bracketModel = mongoose.Schema(
{
tournamentName: String,
gameType: String,
players: Number,
description: String,
teams: [String],
},
{
collection: "bracketsample",
}
);
here is my function
module.exports.addprocesspage = (req, res, next) => {
let newbracket = Bracket({
tournamentName: req.body.tournamentName,
gameType: req.body.gameType,
players: req.body.players,
description: req.body.description,
$addToset:{teams:[req.body.teams]},
});
Bracket.create(newbracket, (err, Bracket) => {
if (err) {
console.log(err);
res.end(err);
} else {
//refresh the bracket-list
res.redirect("/bracket-list");
console.log();
}
});
};
tried declaring cons varialble=req.body.teams but still not working.

You are missing the "new" syntax before "Bracket". Also you use the create method with the already created "Bracket", i would use save instead. Try this:
let newBracket = new Bracket({
tournamentName: req.body.tournamentName,
gameType: req.body.gameType,
players: req.body.players,
description: req.body.description,
$addToset:{teams:[req.body.teams]},
});
newBracket.save().then(() => {
res.redirect("/bracket-list");
}).catch((err) => {
console.log(err);
res.end(err);
});

Related

Updating DB Shema in Express JS with Mongoose library

I have created a Mongo DB schema with Mongoose in Express.js and I am building the REST API. However when I try to update existing records the values that I do not update from the schema automatically become null. I understand why this happens just not sure exactly how it should be coded.
This is the route:
router.patch("/:projectId", async (req, res) => {
try {
const updatedProject = await Project.updateOne(
{ _id: req.params.projectId },
{
$set: {
title: req.body.title,
project_alias: req.body.project_alias,
description: req.body.description
}
}
);
res.json(updatedProject);
} catch (err) {
res.json({ message: err });
}
});
also here is the schema:
const ProjectsSchema = mongoose.Schema({
title: {
type: String,
required: true,
unique: true
},
project_alias: {
type: String,
unique: true,
required: true
},
description: String,
allowed_hours: Number,
hours_recorded: {
type: Number,
default: 0
},
date_added: {
type: Date,
default: Date.now
}
});
My problem is that when I want to update just the title:
{
"title" : "Title Updated33"
}
description and alias become null. Should I implement a check?
Just use req.body for the update object like this:
router.patch("/:projectId", async (req, res) => {
try {
const updatedProject = await Project.updateOne(
{ _id: req.params.projectId },
req.body
);
res.json(updatedProject);
} catch (err) {
res.json({ message: err });
}
});
Or even better, create a helper function like this so that we can exclude the fields in the body that doesn't exist in the model:
const filterObj = (obj, ...allowedFields) => {
const newObj = {};
Object.keys(obj).forEach(el => {
if (allowedFields.includes(el)) newObj[el] = obj[el];
});
return newObj;
};
router.patch("/:projectId", async (req, res) => {
const filteredBody = filterObj(
req.body,
"title",
"project_alias",
"description",
"allowed_hours",
"hours_recorded"
);
try {
const updatedProject = await Project.updateOne(
{ _id: req.params.projectId },
filteredBody
);
res.json(updatedProject);
} catch (err) {
res.json({ message: err });
}
});

How to use findByIdAndUpdate on mongodb?

I am a noobie in coding and I am having an issue with how to use properly MongoDB. I have a parent object classroom containing an array of objects - comments. I am trying to update the content of 1 selected comment.
originally I updated the state of the whole "classroom" in the react and passed all the data and $set {req.body} in findByIdAndUpdate.
I want to achieve the same result if I only pass to my axios request classId, commentId and comment data and not whole classroom / all comments
I tried to filter selected comment out of the array of comments and concat updated comment, but that did not work. Clearly, I have any idea what is going on and docs don't make it any easier for me to understand.
my classroom schema:
var ClassroomSchema = new Schema({
title: String,
teacher: String,
info: String,
image_url: String,
comments: [Comment.schema]
});
comment schema:
var CommentSchema = new Schema()
CommentSchema.add({
content: String,
comments: [CommentSchema],
created_at: {
type: Date,
default: Date.now
}
});
original solution:
function update(req, res){
Comment.findById(req.params.comment_id, function(err, comment) {
if(err) res.send(err)
comment.content = req.body.content;
comment.save();
console.log(req.body.comments)
Classroom.findByIdAndUpdate(req.params.classroom_id,
{$set: req.body}, function(err, classroom){
if (err) {
console.log(err);
res.send(err);
} else {
commentToUpdate = req.body.commentData;
res.json(classroom);
}
});
});
}
my current failing atempt:
function update(req, res){
console.log('update => req.body: ', req.body);
console.log('req.params', req.params)
Comment.findById(req.params.comment_id, function(err, comment) {
if(err) res.send(err)
comment.content = req.body.content;
comment.save();
console.log('comment: ', comment);
Classroom.findById(req.params.classroom_id, function(err, classroom) {
console.log('CLASSROOM findByIdAndUpdate classroom: ', classroom)
// console.log('reg.body: ', req.body)
if (err) {
console.warn('Error updating comment', err);
res.send(err);
} else {
// commentToUpdate = req.body.commentData;
old_comments = classroom.comments;
console.log('comments: ', old_comments);
Classroom.findByIdAndUpdate(req.params.classroom_id,
{$set:
{ comments: old_comments.filter(comt._id !== comment._id).concat(comment)}
}, function(err, updatedClassroom) {
if (err) {
console.warn(err);
} else {
res.json(updatedClassroom);
}
});
}
});
});
}
haven't tested, but try this.
function update(req, res) {
Classroom.update(
{ _id: req.params.classroom_id, "comments._id": req.params.comment_id },
{ $set: { "comments.$.content": req.body.content } },
function(err) {
..
}
);
}

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
})
}

Update field within nested array using mongoose

I'm trying to update the subdocument within the array without success. The new data doesn't get saved.
Express:
router.put('/:id/:bookid', (req, res) => {
library.findOneAndUpdate(
{ "_id": req.params.id, "books._id": req.params.bookid},
{
"$set": {
"title.$": 'new title'
}
}
});
LibraryScema:
const LibarySchema = new Library({
Name: {
type: String,
required: false
},
books: [BookSchema]
});
bookScema:
const BookSchema = new Schema({
title: {
type: String,
required: false
},
Chapters: [
{
chapterTitle: {
type: String,
required: false
}
}
]
});
I only aim to update the sub-document, not parent- and sub-document at same time.
I had a similar issue. I believe there is something wrong with the $set when it comes to nested arrays (There was an entire issue thread on GitHub). This is how I solved my issue.
var p = req.params;
var b = req.body;
Account.findById(req.user._id, function (err, acc) {
if (err) {
console.log(err);
} else {
acc.websites.set(req.params._id, req.body.url); //This solved it for me
acc.save((err, webs) => {
if (err) {
console.log(err);
} else {
console.log('all good');
res.redirect('/websites');
}
});
}
});
I have a user with a nested array.
Try this code
router.put('/:id/:bookid', (req, res) => {
library.findById(
req.params.id, (err, obj) => {
if (err) console.log(err); // Debugging
obj.books.set(req.params.bookid, {
"title": 'new title',
'Chapters': 'your chapters array'
});
obj.save((err,obj)=>{
if(err) console.log(err); // Debugging
else {
console.log(obj); // See if the saved object is what expected;
res.redirect('...') // Do smth here
}
})
})
});
Let me know if it works, and I'll add explanation.
Explanation: You start by finding the right object (library in this case), then you find the correct object in the array called books.
Using .set you set the whole object to the new state. You'll need to take the data that's not changing from a previous instance of the library object.
I believe this way will overwrite and remove any data that's not passed into the .set() method. And then you save() the changed.

How to link a collection with user?

I am working on MEAN application(Angular2+). I want to maintain a seprate data for each user. As of now the data are like anyone can view any of the details but i want like, If i login and enter details, only I can view those details. Basically I want to link user collection with other collection. Since I am new to Mongo, I have no idea about this.
user.ts
import * as mongoose from 'mongoose'
const userSchema = new mongoose.Schema({
username: String,
email: { type: String, unique: true, lowercase: true, trim: true },
password: String,
role: String
});
cat.ts
import * as mongoose from 'mongoose';
const catSchema = new mongoose.Schema({
name : String,
height: String,
weight: String,
});
I have no idea what is this
base.ts
abstract class BaseCtrl {
abstract model: any;
// Get all
getAll = (req, res) => {
this.model.find({}, (err, docs) => {
if (err) { return console.error(err); }
res.json(docs);
});
}
// Count all
count = (req, res) => {
this.model.count((err, count) => {
if (err) { return console.error(err); }
res.json(count);
});
}
// Insert
insert = (req, res) => {
const obj = new this.model(req.body);
obj.save((err, item) => {
// 11000 is the code for duplicate key error
if (err && err.code === 11000) {
res.sendStatus(400);
}
if (err) {
return console.error(err);
}
res.status(200).json(item);
});
}
// Get by id
get = (req, res) => {
this.model.findOne({ _id: 'req.params.id '}, (err, obj) => {
if (err) { return console.error(err); }
res.json(obj);
});
}
// Update by id
update = (req, res) => {
this.model.findOneAndUpdate({ _id: req.params.id }, req.body, (err) => {
if (err) { return console.error(err); }
res.sendStatus(200);
});
}
// Delete by id
delete = (req, res) => {
this.model.findOneAndRemove({ _id: req.params.id }, (err) => {
if (err) { return console.error(err); }
res.sendStatus(200);
});
}
}
export default BaseCtrl;
Reference project : https://github.com/DavideViolante/Angular-Full-Stack
You need to add user_id field to catSchema. The user_id will be the reference for the user who add/save that cat.
cat.ts
import * as mongoose from 'mongoose';
const catSchema = new mongoose.Schema({
name : String,
height: String,
weight: String,
user_id: String, // Or may be ObjectId
});
And you need to query the user from users collection to retrieve the data everytime.
Or you can use DBRef of mongodb. To implement this in mongoose you can follow this link.
Basically your cat model will be
cat.ts
import * as mongoose from 'mongoose';
const catSchema = new mongoose.Schema({
name : String,
height: String,
weight: String,
user: { type: mongoose.Schema.ObjectId, ref: 'User' }
});
To insert the cat, get the userid from login details/sessions and add to collection.
For you, you need to add the 'user' field to req.body as in base controller you are creating model from req.body.
If you don't want to add to req.body, you can override the insert method for cat controller and manually create the cat model with userid.
controller/cat.ts
import Cat from '../models/cat';
import BaseCtrl from './base';
export default class CatCtrl extends BaseCtrl {
model = Cat;
insert = (req, res) => {
const data = {
title: req.body.title,
height: req.body.height,
weight: req.body.weight,
user: getUser() // Get the logged in userid
};
const obj = new this.model(data);
obj.save((err, item) => {
if (err && err.code === 11000) {
res.sendStatus(400);
}
if (err) {
return console.error(err);
}
res.status(200).json(item);
})
}
}
Just like above, you can modify and filter all your documents according to user.
Edit:
To make it simple, send the current logged in user in the form itself. cats.component.ts
addCat() {
this.addCatForm.value.userid = this.authService.currentUser._id; // You might need to use callback here
... // All other code
}
Revert the cat controller to as it was before.

Resources