Hello this is the first time I post a question.
So basically i'm build an API to manage car(Im doing this as a training for better building API). My connection to the D is made using a singleton which is called once by server and the mongo promises are global(and it works fine for now)
I have my model:
import mongoose, {Schema} from "mongoose";
import mongooseUniqueValidator from "mongoose-unique-validator";
class Voiture{
initSchema(){
const schema = new Schema({
Marque:{
type: String,
require:true,
},
Modele:{
type: String,
require:true,
},
Année:{
type: Number,
require:true,
},
Energie:{
type: String,
require:true,
},
Boite_De_Vitesse:{
type: String,
require:true,
},
couleur_exterieure:{
type: String,
require:true,
},
couleur_intérieur:{
type: String,
},
nombre_De_Portes:{
type: Number,
},
nombre_De_Places:{
type: Number,
},
Prix:{
type: Number,
},
Etat:{
type: String,
require: true,
},
Kilométrage:{
type: Number,
},
prix_location:{
type: Number,
require:true,
}
},{timestamp: true});
schema.plugin(mongooseUniqueValidator);
mongoose.model("voitures", schema);
}
getInstance() {
this.initSchema();
return mongoose.model("voitures");
}
}
export default Voiture;
and I also have services and controllers attached to them
I can get all the documents in the mongoDB Database but I can't create Documents
Here is my service
import voiture from "../models/Voiture"
import mongoose from "mongoose"
class VoitureService{
constructor(){
this.model = new voiture().getInstance();
this.getAll = this.getAll.bind(this);
this.insert = this.insert.bind(this);
}
/**
* GET All voiture
*/
async getAll(query){
let {skip, limit} = query;
skip = skip ? Number : 0;
limit = limit ? Number : 10;
delete query.skip;
delete query.limit;
if(query._id){
try {
query._id = new mongoose.mongo.ObjetId(uery._id);
} catch (error) {
console.log("not able to generate mongoose id with content", query._id);
}
}
try {
let items = await this.model
.find(query)
.skip(skip)
.limit(limit)
let total = await this.model.countDocuments();
return {
error: false,
statusCode: 200,
data: items,
total
};
} catch (errors) {
return {
error: true,
statusCode: 500,
errors
};
}
}
/**
* Insert a car in the Database
*/
async insert(data){
console.log("line 60");
try {
console.log("line 62");
let item = await this.model.create(data, function (err) {
console.log("line 64");
if (err) return handleError(err);
// saved!
console.log("line 67");
});
if (item){
console.log("line 70");
return {
error: false,
item
};
}
} catch (error) {
console.log("error", error);
return {
error: true,
statusCode: 500,
message: error.message || "Not able to create item",
errors: error.errors
};
}
}
}
And this my controller
async addCar(req, res){
let response = await this.service.insert(req.body)
if (res.error) return res.status(res.statusCode).send(response);
return res.status(201).send(response);
}
I tried to log the Item but it gives me undefined
Thanks to all of you !
Salayna
You can Follow this code
// At Frist, You import **Voiture** Model Then use the model
async insert(data){
console.log("line 60");
try {
console.log("line 62");
let item = await Voiture.create(data, function (err) {
console.log("line 64");
if (err) return handleError(err);
// saved!
console.log("line 67");
});
if (item){
console.log("line 70");
return {
error: false,
item
};
}
} catch (error) {
console.log("error", error);
return {
error: true,
statusCode: 500,
message: error.message || "Not able to create item",
errors: error.errors
};
}
}
Related
I am trying to add query params that allow the api user to have the option to sort by descending order based on the title field and to limit the the amount items the query returns. But when I call the endpoint it still just returns the data unsorted and without the limit applied to it.
getCourses = async (req, res) => {
try {
const limit = req.query.limit | 20;
if (req.query.desc === "true") {
const data = await courseModel.find().sort({ title: -1 }).limit(limit);
return res.json(data);
} else {
const data = await courseModel.find().aggregate({ $limit: limit });
return res.json(data);
}
} catch (error) {
return res.status(500).json({ message: error.message });
}
};
const courseSchema = mongoose.Schema({
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
category: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
length: {
type: Number,
required: true
}
})
const CourseMessge = mongoose.model('CourseMessage', courseSchema);
module.exports = CourseMessge
This is how i am calling the end point:
localhost:3000/api/courses?desc=true&limit=10
You should use the || operator for specifying a default value for the limit.
Also, try to cast the desc parameter to a string:
getCourses = async (req, res) => {
try {
const limit = req.query.limit || 20;
if (req.query.desc.toString() === 'true') {
const data = await courseModel.find().sort({ title: -1 }).limit(limit);
return res.json(data);
} else {
const data = await courseModel.find().limit(limit);
return res.json(data);
}
} catch (error) {
return res.status(500).json({ message: error.message });
}
};
I am simply trying to update the content according to the id, but whichever id I am using, it updates only the first id by overriding it.
The flow goes as routes => controller => repository
Following is the code:
Routes =>
router.post("/:pageId/content", async (req, res, next) => {
try {
const pageId = req.params;
const pageContent = req.body;
if (!pageId || !pageContent) {
throw {
statusCode: 200,
customMessage: "All parameters are required"
};
}
const result: any = await webpageController.createContent(
pageId,
pageContent
);
if (result.isError) {
throw result.error;
}
res.status(200).json(result.data);
} catch (error) {
next(error);
}
});
Controller =>
const createContent = async (pageId: any, pageContent: any) => {
try {
// calls repository to create content
const result = await webpageRepository.createContent(pageId, pageContent);
// if result is not success, throw error
if (!result.success) {
throw {
statusCode: 400,
customMessage: "Unable to create web page content"
};
}
return {
isError: false,
data: result.data
};
Repository =>
export const createContent = async (pageId: any, content: any) => {
try {
const result = await webpage.findOneAndUpdate(pageId, { content });
return {
data: result,
success: true
};
} catch (error) {
logger.error(
`at:"repositories/webpage/createContent" => ${JSON.stringify(error)}`
);
return {
success: false
};
}
};
Here it can be seen that the id I have used in the route and the id getting updated is different.
What am I doing wrong here?
Following is the schema:
const mongoose = require('mongoose');
const { Schema } = mongoose;
const webpage = new mongoose.Schema(
{
name: {
type: String,
required: true,
trim: true,
maxlength: 25,
},
slug: {
type: String,
// required: true,
},
url: {
type: String,
required: true,
unique: true
},
content: Object,
},
{
timestamps: true,
},
);
export default mongoose.model('webpages', webpage);
I think you should use a dictionary as the parameter.
const result = await webpage.findOneAndUpdate({_id:pageId.pageId}, {content});
You can check on this documentation about how to use the "findOneAndUpdate" https://mongoosejs.com/docs/tutorials/findoneandupdate.html#getting-started
This worked for me
const result = await webpage.findOneAndUpdate( {_id:pageId.pageId} , { content });
i was following some react/express tutorials.
im confused with code below in contacts.js file
if (!contact) {
return res.status(404).json({ msg: "Contact not found" })
}
Is above code necessary ? or whats is there better way to catch if the contact doesn't exist in mongodb ?
when i do put request from postman with invalid id for example
localhost:44022/api/contacts/<invalid ID>
the execution never reach if (!contact) part. if i console log the catch(err) section i get something below
CastError: Cast to ObjectId failed for value "bcvbxcxc" at path "_id" for model "contact"
at model.Query.exec (/Users/becker/Desktop/RJS/ckeeper/node_modules/mongoose/lib/query.js:4380:21)
at model.Query.Query.then (/Users/becker/Desktop/RJS/ckeeper/node_modules/mongoose/lib/query.js:4472:15)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
messageFormat: undefined,
stringValue: '"bcvbxcxc"',
kind: 'ObjectId',
value: 'bcvbxcxc',
path: '_id',
reason: Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters
at new ObjectID (/Users/becker/Desktop/RJS/ckeeper/node_modules/bson/lib/bson/objectid.js:59:11)
contacts.js
router.put('/:id', auth, async (req, res) => {
const { name, email, phone, type } = req.body;
const contactFields = {};
if (name) contactFields.name = name;
if (email) contactFields.email = email;
if (phone) contactFields.phone = phone
if (type) contactFields.type = type;
try {
let contact = await Contact.findById(req.params.id);
if (!contact) {
return res.status(404).json({ msg: "Contact not found" })
}
//makesure contact belongs to right user
if (contact.user.toString() != req.user.id) {
return res.status(401).json({ msg: 'Not authorized' })
}
contact = await Contact.findByIdAndUpdate(req.params.id, { $set: contactFields }, { new: true })
res.json(contact)
}
catch (err) {
console.log("reached error, contact not found")
console.error(err)
res.status(500).send(err)
}
});
Contacts.js model
const mongoose = require('mongoose');
const ContactSchema = mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'users'
},
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
},
phone: {
type: String
},
type: {
type: String,
default: 'personal'
},
date: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('contact', ContactSchema)
The reason for not executing the if(!contact) condition upon exception is because catch block will be called and further execution in the try block is halted. You should rather wrap each db call in its own try catch block. Something like:
let contact;
try {
contact = await Contact.findById(req.params.id);
} catch(err) {
console.log('Some db operations failed due to reason', err);
return res.status(500).json({ msg: "DB operations failed or whatever message" })
}
if (!contact) {
return res.status(404).json({ msg: "Contact not found" })
}
//makesure contact belongs to right user
if (contact.user.toString() != req.user.id) {
return res.status(401).json({ msg: 'Not authorized' })
}
try {
contact = await Contact.findByIdAndUpdate(req.params.id, { $set: contactFields }, { new: true })
return res.json(contact)
}
catch (err) {
console.log("db update operations failed")
console.error(err)
res.status(500).send(err)
}
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 });
}
});
I'm using mongoose Model.findOneAndupdate() to find and update my document and there is a post hook on my model schema for which i'm trying to update another document.
The issue i'm facing is post hook is being triggered twice.
My model:
const mongoose = require('mongoose')
const componentSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
component: {
type: String,
required: true
},
message: {
type: String
},
bodyJson: {
type: mongoose.Schema.Types.Mixed
},
question: {
type: String
}
})
componentSchema.post('findOneAndUpdate', function (result) {
console.log('came here')
})
module.exports = mongoose.model('Component', componentSchema)
In my server log i see that came here logged is twice.
update:
try {
await Component.findOneAndUpdate(query, req.body, { new: true }, function (error, doc) {
if (doc) {
return res.status(200).json({ data: doc })
} else if (error) {
return res.status(400).json({ errors: error.message })
} else res.status(404).json({ errors: 'Not found' })
})
} catch (error) {
logger.error('error while updating order: ' + error)
return res.status(400).json({ errors: error.message })
}
moongoose version i'm using is 5.8.11
You are using both await and callback at the same time. This causes the middleware trigger 2 times. Only one of them must be used.
Use either callback:
Component.findOneAndUpdate(query, req.body, { new: true }, function(
error,
doc
) {
if (err) {
return res.status(400).json({ errors: error.message }); //500 status code may be better
} else {
if (doc) {
return res.status(200).json({ data: doc });
} else {
res.status(404).json({ errors: "Not found" });
}
}
});
Or await:
try {
const doc = await Component.findOneAndUpdate(query, req.body, { new: true });
if (doc) {
return res.status(200).json({ data: doc });
} else {
res.status(404).json({ errors: "Not found" });
}
} catch (error) {
logger.error("error while updating order: " + error);
return res.status(400).json({ errors: error.message });
}