Don't know how to deal with it - node.js

Hello guys i am validating product create request in my validate middleware then if it validates it goes to products/create endpoint problem i am having is that to create product you need userId so i know which user created it, for it i decode my jwt token in products/create endpoint and then assign it to product when creating it. but problem is that product shouldn't have same title name for same user for example user A can't have 2 products with same title idk how i can do that cuz i decode jwt in the final enpoint while i validate request in the middleware
schema for validating
export const productCreateSchema = yup.object().shape({
title: yup.string().required('Product title is required'),
price: yup.number().required('Product price is required').min(5),
type: yup
.string()
.oneOf(['pullover', 'jeans', 'jacket', 'hoodie'])
.required('Product type is required'),
condition: yup
.string()
.oneOf(['new', 'old'])
.required(`Product condition is required`),
size: yup
.string()
.oneOf(['xs', 's', 'm', 'xl', 'xll', 'xxl'])
.required('Product size is required'),
});
endpoint
router.post('/', async (req: CustomRequest, res) => {
const { title, price, type, condition, size } = req.body;
const conditionRecord = await ProductCondition.findOne({
where: { condition },
});
const typeRecord = await ProductType.findOne({
where: { type },
});
const sizeRecord = await ProductSize.findOne({
where: { size },
});
console.log('req.user: ', req.user);
Product.create({
user_id: req.user!.userId,
title: req.body.title,
price: req.body.price,
type_id: typeRecord!.dataValues.id,
condition_id: conditionRecord!.dataValues.id,
size_id: sizeRecord!.dataValues.id,
});
res.status(200).send('test'); // i actually send some data but its too big to post
});
export default router;```
temp temp temp temp temp temp

Related

How do I add expenses for only specific users?

I have created two models in my app- one for User (_id, email, username, password) and one for Expense (_id, date, detail, amount, category). For the users, I have finished the authentication with jwt.
I want logged-in users to be able to add/remove expenses and not show their expenses to other users but I don't know how I can implement that. I am not asking for code- I would be grateful if you could roughly tell me what I need to do. Thanks!
//expense schema
const expenseSchema = new mongoose.Schema(
{
date: Date,
detail: String,
amount: Number,
category: String
}
)
//controller for adding expenses
const addExpenseController = (req, res) => {
const expense = new Expense({
"date": new Date(),
"amount": req.body.amount,
"detail": req.body.detail,
"category": "expense"
});
expense.save();
res.send('expense added');
};
You should define a ref property in the expense schema pointing at the User model (change the value of the ref attribute to equal the model name given to the users):
const expenseSchema = new mongoose.Schema(
{
...
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
}
)
Then, on creation, specify the user by setting the value of its _id.
You can either store it in the session or pass it in the body, depending on your implementation:
const addExpenseController = async (req, res) => {
try {
const expense = new Expense({
date: new Date(),
amount: req.body.amount,
detail: req.body.detail,
category: 'expense',
user: req.session.user_id, // or req.body.user_id
});
await expense.save();
res.send('expense added');
} catch (err) {
res.send('server error');
}
};

I want to merge json data fetched from first api to second api data. Both api have userid as parameter in common. Please help me

app.get("/user/:id", (request, res)=>{
async function getToDoUser(){
const todoData = await fetch('https://jsonplaceholder.typicode.com/todos');
this api contains 200 entries
const response = await todoData.json();
const kuch = request.params.id;
const todoUserData = await fetch(`https://jsonplaceholder.typicode.com/users/${kuch}`);
this api will only give one entry
const userResponse = await todoUserData.json();
let responseArray = [];
var todos = {};
var target = {};
for(let i = 0; i<response.length;i++){
todos = new todoModel({
userId: response[i]["userId"],
id: response[i]["id"],
title: response[i]["title"],
completed: response[i]["completed"]
})
I have added the entries from 1st api
responseArray.push({userId: response[i]["userId"],
id: response[i]["id"],
title: response[i]["title"],
completed: response[i]["completed"]
})
}
const todoUser = new todoUserModel({
userid: userResponse["userid"],
name: userResponse["name"],
username: userResponse["username"],
email: userResponse["email"],
address: {
street: userResponse['address["street"]'],
suite: userResponse['address["suite"]'],
city: userResponse['address["city"]'],
zipcode: userResponse['addresss["zipcode"]'],
geo: {
lat:userResponse['address[geo["lat"]]'],
lng: userResponse['address[geo["lng"]]']
}
},
phone: userResponse["phone"],
website: userResponse["website"],
company: {
name: userResponse['company["nam"]'],
catchPhrase: userResponse['company["catchPhrase"]'],
bs: userResponse['company["bs"]']
},
till here 2nd api gives data and from here i want to add data from 1st api where the user id should be equal
todo: {
userId: response['0']['userid'],
userid in todo should be equal to userid in todoUser
all entries from todo with userid same as userid in todouser api
id: response['0']['id']
}
})
_.extend(target, todoUser);
// here i have merged data from todouser to new json object named target
res.send(target);
// here sending response
}
getToDoUser();
})

Req.body returns undefined : ExpressJs, NodeJs

Please help me I'm having this error for 5 days.
I'm trying to delete data inside of my array on MongoDB
but my req.body returns undefined even though I have my body-parser. I'm using axios.patch for request.
It works well in my postman but once I sent data that's where the problem occurs.
Here's my axios api call.
export const deleteTask = (id,post) => api.patch(`/main/${id}`, post);
Here's my schema.
const todoSchema = mongoose.Schema({
username: {
type: String,
},
password: {
type: String,
},
task: [String],
time: {
type: Date,
default: Date.now,
}
});
const TodoModels = mongoose.model('TodoModels', todoSchema);
here's my query.
export const deleteTask = async (req,res) => {
const { id } = req.params;
console.log(req.body);
if(!mongoose.Types.ObjectId.isValid(id))
return res.status(404).json(`Invalid ID`);
await TodoModels.findByIdAndUpdate(id,{$pull:{ task: req.body.task }},{
new: true });
}
My req.body has no task and I don't know why. Once I send data it returns undefined but the ID from req.params is not undefined.
Also once I sent the data from client to backend/server req.body returns this { data: '' } the data I sent became the element. I believe it was supposed to be { task: 'data' }
If your deleting a record then why are you using findByIdAndUpdate ; it should be findByIdAndDelete. I have put a sample code you to refer. There are 2ways you can delete a record. You can try them out and see.
Way 1:
router.delete('/:id', [auth, admin, validateObjectId], async(req, res) => {
//check for existing genre
const movieGenre = await Genre.findByIdAndDelete(req.params.id);
if (!movieGenre) {
return res.status(404).send('No such movie genre found with given id.');
}
res.send(movieGenre);
})
Way 2:
router.delete('/:id', [auth, admin, validateObjectId], async(req, res) => {
//second way to delete
let movieGenre = await Genre.findById(req.params.id);
if (!movieGenre) {
return res.status(404).send('No such movie genre found with given id.');
}
await movieGenre.deleteOne();
const index = genres.indexOf(movieGenre);
genres.splice(index, 1);
res.send(movieGenre);
})
Hope the answer helps you in any way.

Unable to update MongoDB collection by matching _id

First, I Registered a user using His email and password.
Now if
I try to Update or Make user details by matching the Id assigned by the Mongo Database while registering the user.
it's not accepting it.
error is like this
Parameter "filter" to find() must be an object, got 60b10821af9b63424cf427e8
if I parse it like
Model.find(parseInt(req.params.id))
it shows a different error.
Well here's the Post Request
//Post request to create user details by matching Id.
// Id I am trying to match is the id that was given by the database
app.post("/user/:id", async(req, res) => {
console.log("not found");
if (await Model.find(req.params.id)) {
const users = new Model({
fName: req.body.fName,
sName: req.body.sName,
birth: req.body.birth,
phone: req.body.phone,
SSN: req.body.SSN
});
const result = await users.save();
console.log(result);
return res.send({
"Success": true,
});
} else {
console.log(req.params.id);
res.status(404).send({ "message": false });
}
});
Here's the schema
const LoginSchema = new mongoose.Schema({
email: { type: String, required: true },
password: { type: String, required: false },
otp: String,
token: String,
fName: String,
sName: String,
birth: Number,
phone: Number,
SSN: Number
});
Here are the headers I used
const express = require("express");
const app = express();
const mongoose = require("mongoose");
app.use(express.json());
app.use(express.urlencoded({ extend: true }));
Database id assigned which I use
{
_id: 60b1131271129a3cf8275160,
email: 'Pak#gmail.com',
password: '$2b$10$FWAHu4lP9vn14zS/tWPHUuQJlO7mjAUTlPj.FliFAZmCNA23JA3Ky',
__v: 0
}
The error:
Parameter "filter" to find() must be an object, got 60b10821af9b63424cf427e8
means: You need to provide an object as the argument of the find() method, not a string ("60b10821af9b63424cf427e8" in this case). Moreover, find() will give you an array, if you find an item in the database, use findOne() instead.
Change from :
await Model.find(req.params.id)
to :
await Model.findOne({_id : req.params.id})
Another way is to use findById() method like this : await Model.findById(req.params.id)
Likely the error is caused by the fact that you're passing a string from the request when Mongoose is expecting an instance of mongoose.Types.ObjectId. You should be able to fix the problem by casting the string into said type.
await Model.find(mongoose.Types.ObjectId(req.params.id))

Saving data to array in mongoose

Users are able to post items which other users can request. So, a user creates one item and many users can request it. So, I thought the best way would be to put an array of users into the product schema for who has requested it. And for now I just want to store that users ID and first name. Here is the schema:
const Schema = mongoose.Schema;
const productSchema = new Schema({
title: {
type: String,
required: true
},
category: {
type: String,
required: true
},
description: {
type: String,
required: true
},
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
requests: [
{
userId: {type: Object},
firstName: {type: String}
}
],
});
module.exports = mongoose.model('Product', productSchema);
In my controller I am first finding the item and then calling save().
exports.postRequest = (req, res, next) => {
const productId = req.body.productId;
const userId = req.body.userId;
const firstName = req.body.firstName;
const data = {userId: userId, firstName: firstName};
Product.findById(productId).then(product => {
product.requests.push(data);
return product
.save()
.then(() => {
res.status(200).json({ message: "success" });
})
.catch(err => {
res.status(500).json({message: 'Something went wrong'});
});
});
};
Firstly, is it okay to do it like this? I found a few posts about this but they don't find and call save, they use findByIdAndUpdate() and $push. Is it 'wrong' to do it how I have done it? This is the second way I tried it and I get the same result in the database:
exports.postRequest = (req, res, next) => {
const productId = req.body.productId;
const userId = req.body.userId;
const firstName = req.body.firstName;
const data = {userId: userId, firstName: firstName};
Product.findByIdAndUpdate(productId, {
$push: {requests: data}
})
.then(() => {
console.log('succes');
})
.catch(err => {
console.log(err);
})
};
And secondly, if you look at the screen shot is the data in the correct format and structure? I don't know why there is _id in there as well instead of just the user ID and first name.
Normally, Developers will save only the reference of other collection(users) in the collection(product). In addition, you had saved username also. Thats fine.
Both of your methods work. But, second method has been added in MongoDB exactly for your specific need. So, no harm in using second method.
There is nothing wrong doing it the way you have done it. using save after querying gives you the chance to validate some things in the data as well for one.
and you can add additional fields as well (if included in the Schema). for an example if your current json return doesn't have a field called last_name then you can add that and save the doc as well so that's a benefit..
When using findById() you don't actually have the power to make a change other than what you program it to do
One thing I noticed.. In your Schema, after you compile it using mongoose.modal()
export the compiled model so that you can use it everywhere it's required using import. like this..
const Product = module.exports = mongoose.model('Product', productSchema);

Resources