I want update Category with validate Author
I have two models:
Category: { id, title, description, author } //author contains userId
User: { id, name, categories } //categories contain categoryId.
I want to check: Only author can update author's category, if you are not author, you can not update this category. How can I do it?
My code without findByIdAndUpdate():
My code with findByIdAndUpdate():
const update = async (id, updatedCategory, authorId) => {
try {
const { title, description } = updatedCategory
const query = {
...(title && { title }),
...(description && { description }),
date: Date.now(),
}
let category = await Category.findByIdAndUpdate(id, query,
(error, doc) => {
return doc
}
if (!category) throw "Can not find category"
// How to validate with authorId?
return category
} catch (error) {
throw error
}
}
You need to make little modification in query. Instead of findByIdAndUpdate use findOneAndUpdate.
const update = async (id, updatedCategory, authorId) => {
try {
const { title, description } = updatedCategory
const query = {
...(title && { title }),
...(description && { description }),
date: Date.now(),
}
let category = await Category.findOneAndUpdate({_id:id, author:authorId}, query,
(error, doc) => {
return doc
}
if (!category) throw "Can not find category"
// How to validate with authorId?
return category
} catch (error) {
throw error
}
}
Related
I don't know If I'm checking for the value of the boolean correctly
what this code does: the user creates a note for himself, his ID is on the note and it needs to belong to a category name that has to be in the category schema ( where my error happens )
exports.postAddNote = (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
const error = new Error("validation failed, entered data is incorrect");
throw error;
}
const content = req.body.content;
const tags = req.body.tags;
const categoryName = req.body.categoryName;
let creator;
const note = new Note({
content: content,
categoryName: categoryName, // work
tags: tags,
creator: req.userId,
});
Category.find()
.select("-_id")
.select("-__v")
.select("-notesId")
.then((categories) => {
console.log(categories); //stripping everything but names off categories
const CategoryExists = categories.some(
(category) => category.name === categoryName
);
console.log(CategoryExists); // ~~~~~~~~~~ this logs correctly
if (CategoryExists === -0) { // ~~~~~~~~~~ what i want: if the value is false
return res.json({ Error: "The category you entered does not exist" });
}
note // ~~~~~~~~~~ the code stops here :/ it doesn't save the note
.save()
.then((note) => {
console.log("saved note");
User.findById(req.userId);
})
.then((user) => {
creator = user;
user.notes.push(note);
return user.save();
})
.then((result) => {
res.status(201).json({
info: {
dateCreated: new Date().toISOString(),
status: "Note Created Successfully",
creator: { _id: creator._id, email: creator.email },
},
});
})
.catch((err) => {
if (!err.statusCode) {
err.statusCode = 500;
}
});
})
.catch((err) => {
console.log(err);
next();
});
};
if (CategoryExists === -0)
should be
if (CategoryExists === false)
or just
if (!CategoryExists)
i believe. did you try that? not sure why you are using -0. the return value for some() is either going to be true or false.
try this:
if (!CategoryExists) {
return res.json({ Error: 'The category you entered does not exist' });
}
i'm trying to show a user specific data using req.session.user and pass the ID to the criteria i'm building. (every entry also has a user field so i can match) yet it does not work.
The Service :
async function query(filterBy) {
try {
const criteria = _buildCriteria(filterBy);
const collection = await dbService.getCollection('tab');
const tabs = await collection.find(criteria).toArray();
// const userTabs = await collection.find({ user: '62be030cb4de461a8462b863' }).toArray();
return tabs;
} catch (err) {
logger.error('Can not find tabs', err);
throw err;
}
}
The console.log('userId', userId) returns the Id I get from my controller
function _buildCriteria(filterBy) {
const criteria = {};
const { text, genre, userId } = filterBy;
console.log('userId', userId);
if (text) {
const txtCriteria = { $regex: text, $options: 'i' };
criteria.name = txtCriteria;
}
if (genre) {
criteria.genre = { $eq: genre };
}
if (userId) {
criteria.user = { $eq: userId };
}
return criteria;
}
The controller :
async function getTabs(req, res) {
try {
const userId = req?.session?.user?._id;
const filterBy = req.query;
const fitlerUpdated = { ...filterBy, id: userId };
const tabs = await tabService.query(fitlerUpdated);
res.json(tabs);
} catch (err) {
logger.error('Failed to get tabs', err);
res.status(500).send({ err: 'Failer ti get tabs' });
}
}
I tried using
const userTabs = await collection.find({ user: '62be030cb4de461a8462b863' }).toArray()
and it works yet it doens't work along with the criteria.
thanks for any help!
I have realize I accidentally passed the wrong key.
should have been id and not userId
app.get("/api/users/:_id/logs", (req, res) => {
const id = req.params._id;
const { from, to, limit } = req.query;
** Here I tried to search for the matched user and it works successfully: **
User.findById({ _id: id }, (err, user) => {
if (!user || err) {
res.send("Unknown User Id !!");
} else {
**Then I tried to filter the log array with date **
// const username = user.username;
let responObject = {};
if (from) {
responObject["$gte"] = new Date(from).toDateString();
}
if (to) {
responObject["$lte"] = new Date(to).toDateString();
}
let filter = {
_id: id,
};
if (from || to) {
filter.date = responObject;
}
let nonNullLimit = limit ?? 500;
**try to build the array log and return it to the user but it always be empty and never return the exercises for the user **
Exercise.find(filter)
.limit(+nonNullLimit)
.exec((err, data) => {
if (err || !data) {
res.json([]);
} else {
const count = data.length;
const rowLog = data;
const { username, _id } = user;
const log = rowLog.map((item) => ({
description: item.description,
duration: item.duration,
date: new Date(item.date).toDateString(),
}));
console.log(log)
if (from && to) {
res.json({
username,
from: new Date(from).toDateString(),
to: new Date(to).toDateString(),
count,
_id,
log,
});
} else {
res.json({
username,
count,
_id,
log,
});
}
}
});
}
});
});
this is the result when I try to log all the exercises for the user
{"username":"ahmed","count":0,"_id":"62a9aab2743ddfc9df5165f2","log":[]}
I am trying to implement a rate limit on GraphQL Mutation when creating new users. I successfully implemented it in Queries but could not do the same on Mutations, any advice or resource on how I can solve this would be much appreciated.
Thanks in advance.
imports in resolvers/users
const bcrypt = require('bcrypt');
const { UserInputError } = require('apollo-server');
const { getGraphQLRateLimiter } = require('graphql-rate-limit')
const { validateCreateInput } = require('../../util/validators');
const User = require('../../models/User');
rate limiter declaration
const rateLimiter = getGraphQLRateLimiter({ identifyContext: (ctx) => ctx.id });
Query with rate limitation which works fine
Query: {
getUsers: async (parent, args, context, info) => {
try {
const errorMessage = await rateLimiter(
{ parent, args, context, info },
{ max: 1, window: '3s' }
);
if (errorMessage) throw new Error(errorMessage);
const users = await User.find().sort({ createdAt: -1 });
return users;
} catch (err) {
throw new Error(err);
}
},
},
My problem occurs here on Mutation when trying to create user with rate limit
Mutation: {
async createUser(_, {
createInput: {
name,
email,
role,
password,
confirmPassword
}
}) {
/****** problem here ******/
const errorMessage = await rateLimiter(
{ parent, args, context, info },
{ max: 1, window: '3s' }
);
if (errorMessage) throw new Error(errorMessage);
/****** problem here ******/
const { valid, errors } = validateCreateInput(name, email, role, password, confirmPassword);
if (!valid) {
throw new UserInputError('Errors', { errors })
}
const duplicateEmail = await User.findOne({ email });
if (duplicateEmail) {
throw new UserInputError('Email is already used', {
errors: {
email: 'Email is already used'
}
})
}
password = await bcrypt.hash(password, 12);
const newUser = new User({
name,
email,
role,
password,
createdAt: new Date().toISOString()
})
const res = await newUser.save();
return {
...res._doc,
id: res._id
}
}
}
The error that I am getting while creating new user
The error is pretty clear, check the difference between your query resolver and your mutation resolver. You need something like:
Mutation: {
async createUser(parent, args, context, info) { ... }
}
Then parent and other required fields will be defined.
Whenever I use this function, it will not retrieve data without specifying a title.
The point of this is supposed to be to filter through looking for authorid, and then search.
But if no search "title" is provided, I still want to return all of the Cards.
Can you tell me what in my code I would need to correct in order for this to happen?:
//Finds All of the User's Cards, and allows Searching by Title
exports.findMyCards2 = (req, res) => {
const { page, size, title, authorid } = req.query;
const { limit, offset } = getPagination(page, size);
Card.findAndCountAll({
limit,
offset,
where: {
authorid: { [Op.like]: `%${authorid}%` },
title: { [Op.like]: `%${title}%` || ""} // I tried to add || "" here
}
})
.then(data => {
const response = getPagingData(data, page, limit);
res.send(response);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving Cards."
});
});
};
An SQL LIKE "" is looking for empty values.
So you need to send a different WHERE clause to the DB if there is no title in the request.
//Finds All of the User's Cards, and allows Searching by Title
exports.findMyCards2 = (req, res) => {
const { page, size, title, authorid } = req.query;
const { limit, offset } = getPagination(page, size);
// Your default query
let query = {
authorid: { [Op.like]: `%${authorid}%` },
title: { [Op.like]: `%${title}%`}
}
// Query if the title is undefined (Remove the a title criteria of the WHERE)
if(!title){
query = {
authorid: { [Op.like]: `%${authorid}%` }
}
}
Card.findAndCountAll({
limit,
offset,
where: query // Then use it here
})
.then(data => {
const response = getPagingData(data, page, limit);
res.send(response);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving Cards."
});
});
};