Nodejs:Array data not added in mongodb - node.js

This is my model profile.js
var mongoose = require('mongoose');
const ProfileSchema = mongoose.Schema({
educationinfo: [{
universityname:
{
type: String,
required: true
},
degree:
{
type: String,
required: true
},
coursecompletionyear:
{
type: String,
required: true
},
collegename:
{
type: String,
required: true
},
specialization:
{
type: String,
required: true
},
marks:
{
type: String,
required: true
},
courselevel:
{
type: String,
required: true
}
}]
});
const Profile = module.exports = mongoose.model('Profile', ProfileSchema);
This is my route.js post function
router.post('/addprofiledetails', function(req, res, next) {
let newProfile = new Profile({
$educationinfo:[{
universityname:req.body.universityname,
degree:req.body.degree
}]
});
newProfile.save((err, profile) => {
if (err) {
res.json({ msg: 'Failded to add profiledetails' });
} else {
res.json({ msg: 'successfully add profile details' });
}
});
});
I got success msg in post function but the data not added in mongodb. i don't know where i did mistake .please help me.
In mongoDB I got data like,
{
"educationinfo": [],
"_id": "5bed14b93a107411a0334530",
"__v": 0
}
I want details inside educationinfo, please help.

You need to change schema definition and query.
1.remove required from schema Or apply required to those field that you must provide value.
educationinfo: [{
universityname:
{
type: String,
// required: true
},
degree:
{
type: String,
//required: true
},
coursecompletionyear:
{
type: String,
// required: true
},
collegename:
{
type: String,
// required: true
},
specialization:
{
type: String,
//required: true
},
marks:
{
type: String,
// required: true
},
courselevel:
{
type: String,
// required: true
}
}]
2.change $educationinfo with educationinfo
educationinfo:[{
universityname:req.body.universityname,
degree:req.body.degree
}]

Since you marked the properties of educationinfo as required, you need to provide them when you create an instance of Profile. If you don't want to do that you need to remove the required property from those properties that you won't be supplying on instance creation like below:
const mongoose = require('mongoose');
const ProfileSchema = mongoose.Schema({
educationinfo: [{
universityname:
{
type: String,
required: true
},
degree:
{
type: String,
required: true
},
coursecompletionyear:
{
type: String
},
collegename:
{
type: String
},
specialization:
{
type: String
},
marks:
{
type: String
},
courselevel:
{
type: String
}
}]
});
const Profile = module.exports = mongoose.model('Profile', ProfileSchema);
After making those changes, you need to make one more change in your POST route, change $educationinfo to educationinfo
router.post('/addprofiledetails', function(req, res, next) {
const newProfile = new Profile({
educationinfo:[{
universityname: req.body.universityname,
degree: req.body.degree
}]
});
newProfile.save((err, profile) => {
if (err) {
res.json({ msg: 'Failded to add profiledetails' });
} else {
res.json({ msg: 'successfully add profile details' });
}
});
});

The data you insert is incomplete.
The properties in your schema marked as required: true need to be inserted aswell. Because you do not meet the schema requirements, it is failing.

Related

How to return documents in mongoose and express js which are associated with only logged in user?

Here i have two mongoose models orders and users which have one to many relationship.
user.model.js
import mongoose from "mongoose";
const userSchema = mongoose.Schema(
{
firstname: {
type: String,
required: [true, "Name is required"],
},
lastname: {
type: String,
required: [true, "LastName is required"],
},
email: {
type: String,
required: [true, "Email is required"],
unique: true,
},
password: {
type: String,
required: [true, "Password is required"],
},
isAdmin: { type: Boolean, default: false },
},
{
timestamps: true,
}
);
const User = mongoose.model("User", userSchema);
export default User;
order.model.js
import mongoose from "mongoose";
const orderSchema = mongoose.Schema(
{
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
customerId: { type: String },
paymentIntentId: { type: String },
products: [
{
id: { type: String },
name: { type: String },
category: { type: String },
price: { type: String },
size: { type: String },
color: { type: String },
thumbnail: { type: String },
qty: { type: Number },
},
],
// subTotal: { type: Number, required: true },
total: { type: Number, required: true },
shipping: { type: Object, required: true },
deliveryStatus: { type: String, default: "pending" },
paymentStatus: {
type: String,
required: true,
},
},
{
timestamps: true,
}
);
const Order = mongoose.model("Order", orderSchema);
export default Order;
I have some orders created by different users in my database. Now i am trying to get those specific orders associated with currently logged in user.
order.controller.js
export const getAllOrders = async (req, res) => {
const { _id } = req.user;
// console.log(typeof id);
try {
const orders = await Order.find({userId: _id});
console.log(orders);
res.status(200).json({ orders });
} catch (error) {
res.status(500).json({ msg: error.message });
}
};
I have tried this one but it always return an empty array.

how to insert into deeply nested element API nodejs mongoose

I have 4 nested documents as follow:
//Nested sub document subControl
const SubControlSchema = new Schema({
subControlNo: {
type: String
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
//Nested sub document control
const ControlSubSchema = new Schema({
mainControl: {
type: String
},
subControls: [SubControlSchema],
controlDescription: {
type: String,
trim: true
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
//Nested sub document domain
const DomainSubSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
domainNo: {
type: String,
trim: true
},
domainName: {
type: String,
trim: true
},
domainDescription: {
type: String,
trim: true
},
controls: [ControlSubSchema],
updated: Date,
created: {
type: Date,
default: Date.now
}
});
// framework Schema
const FrameworkSchema = new Schema({
name: {
type: String,
trim: true
},
description: {
type: String,
trim: true
},
regulator: {
type: Schema.Types.ObjectId,
ref: 'Regulator',
default: null
},
client: {
type: Schema.Types.ObjectId,
ref: 'Client',
default: null
},
domains: [DomainSubSchema],
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('Framework', FrameworkSchema);
I'm trying to post a control under the domain which is inside the framework, here's what I have been trying to do:
//Add new control under a specific domain and framework
router.post('/add/:frameworkId/:domainId', auth, async (req, res) => {
try {
const control = req.body.controls; //take the request from the body
const query = { _id: req.params.frameworkId, _id: req.params.domainId };//pushing into the framework model by taking the ID from URL
await Framework.updateOne(query, { $push: { domains: control } }).exec(); //push the query into the framework model
res.status(200).json({
success: true,
controls: control
});
} catch (error) {
res.status(400).json({
// error: 'Your request could not be processed. Please try again.'
error
});
}
});
Data posted in postman:
Link: http://localhost:3000/api/framework/add/6233277f411377367f8ad1c0/6233277f411377367f8ad1c1
{
"controls":
{
"mainControl": "1-5",
"subControls": [{
"subControlNo": "1-4-1"
},
{
"subControlNo": "1-4-2"
}],
"controlDescription": "controlDescriptionTest"
}
}
Response:
{
"success": true,
"controls": {
"mainControl": "1-5",
"subControls": [
{
"subControlNo": "1-4-1"
},
{
"subControlNo": "1-4-2"
}
],
"controlDescription": "controlDescriptionTest"
}
}
Problem: I'm not getting any new data in mongodb , any idea if I'm approaching this the correct way? I'm guessing the data is posted correctly and It's a problem with saving it to the database
Picture of my schema: I want to be able to add elements under the controls:
First if you want your code to insert and not update you should use insertOne and not updateOne, regarding an "update" operation I can see 2 potential "issues" here:
req.params.frameworkId and req.params.domainId come as string type. And I assume the _id field is type ObjectId and not string.
To fix this you just need to cast it to the proper type, like so:
import { ObjectId } from 'mongodb';
...
{ _id: new ObjectId(req.params.frameworkId) }
Both parameters are "querying" the same field (_id), unless this is intentional somehow if these values are different it will never find a document to match, this should be changed.
Lastly if you want to update an existing object if exists, and if not insert then you should use updateOne with the upsert option:
await Framework.updateOne(query, { $push: { domains: control } }, { upsert: true }).exec();

Mongoose How to sort .populate field

I'm work with an user/articles profile system. I have been using the .populate() to render the posts but I cannot get the articles sorted by the date they were created.
I am using the createdAt variable as the main way of ordering the posts displayed.
For reference:
router.get('/:id', async (req, res) => {
const user = await User.findById(req.params.id, function(error) {
if(error) {
req.flash("error", "something went wrong")
res.redirect("/");
}
}).populate('articles')
res.render('users/show',{
user: user
});
and the article.js:
const ArticleSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
author: {
type: String
},
markdown: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
},
slug: {
type: String,
required: true,
unique: true
},
sanitizedHtml: {
type: String,
required: true
},
img: {
type: String
},
type:{
type: String
},
user : { type: Schema.Types.ObjectId, ref: 'User' },
}, {timestamps: true});
In advance thank you all for the help.
There is a property called options in populate,
.populate({
path: 'articles',
options: { sort: { createdAt: -1 } }
})

mongoose expressJS update single field in nested array

I am trying to build edit function in my web app using Mongoose and expressJS as backend, I want to update a single field in lessonLog which is an array of lessonLog with individual objectId, I tried it with the following code but not working as I intended, please advise. thank you in advance!
{
Object _id : 601e7877cc4bc5047860831b ObjectId,
date : 2021-02-05T16:00:00.000+00:00 Date,
tempoMin : 71,
tempoMax : 206,
title : Khulau,
intonation : test,
phrasing : test,
articulation : technique : test,
notes : test ,
}
const studentsSchema = new mongoose.Schema({
name: { type: String, require: true },
email: { type: String, require: true },
contact: { type: String, require: true },
activities: {
exam: { type: String, require: true },
recording: { type: String, require: true },
theory: { type: String, require: true },
competition: { type: String, require: true },
orchestra: { type: String, require: true },
},
teacher: { type: mongoose.Types.ObjectId, require: true, ref: "teachers" },
repertoire: [{ type: String, require: true }],
**lessonLog: [
{
date: { type: Date, require: true },
tempoMin: { type: String, require: true },
tempoMax: { type: String, require: true },
title: { type: String, require: true },
scales: { type: String, require: true },
intonation: { type: String, require: true },
phrasing: { type: String, require: true },
articulation: { type: String, require: true },
technique: { type: String, require: true },
notes: { type: String, require: true },
},**
],
});
here is the query:
const editLessonLog = async (req, res, next) => {
try {
await Students.findOneAndUpdate(
{
lessonLog: { _id: req.body.lessonLogId },
},
{
$set: {
lessonLog: {
date: req.body.lessonDate,
tempoMin: req.body.tempo[0],
tempoMax: req.body.tempo[1],
title: req.body.title,
intonation: req.body.intonation,
phrasing: req.body.phrasing,
articulation: req.body.articulation,
technique: req.body.technique,
notes: req.body.notes,
},
},
}
);
// console.log(student);
} catch (err) {
const error = new HttpError(
"Cannot delete lesson log, please try again.",
500
);
return next(error);
}
you should using $ based on documentation
The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array
so just try
const editLessonLog = async (req, res, next) => {
try {
await Students.findOneAndUpdate(
{
"lessonLog._id": req.body.lessonLogId
},
{
$set: {
"lessonLog.$": {
date: req.body.lessonDate,
tempoMin: req.body.tempo[0],
tempoMax: req.body.tempo[1],
title: req.body.title,
intonation: req.body.intonation,
phrasing: req.body.phrasing,
articulation: req.body.articulation,
technique: req.body.technique,
notes: req.body.notes,
},
},
}
);
// console.log(student);
} catch (err) {
const error = new HttpError(
"Cannot delete lesson log, please try again.",
500
);
return next(error);
}

property pre does not exist on schema in mongoose

I am trying to detect changes in the document via pre hook but it typescript is giving me error that this property does not exist.
following Structured style, not OOP
// category.schema.ts
const categorySchema = new Schema({
category_id: { type: Number, required: true, unique: true },
name: { type: String, required: true, unique: true },
icon_url: { type: String, required: true },
items_quantity: { type: Number, required: true },
items: [
item_id: { type: Number, required: true, unique: true },
item_name: { type: String, required: true }
]
})
const Category: Model<Category> = model<Category>('Category', categorySchema);
export default Category;
Now I want to check for document changes on deletion of subdocument.
import CategorySchema from "../schemas/category.schema"; // schema path
router.delete('/:category/:item', async (req, res) => { // removes an item
let itemsQuantity: number;
let category = await CategorySchema.findOneAndUpdate(
{ category_id: req.params.category },
{ $pull: { items: { item_id: req.params.item } } },
{ new: true });
// pre does not exist
CategorySchema.pre('save', function(next) {
if(category.isModified()) {
log('changed');
} else {
log('not changed')
}
})
const data = await category.save();
res.status(200).send(req.params.item);
})
How to get or enable this hook, any suggestions?

Resources