MongoDB query doesn't find the requested entries - javascript

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

Related

Can't get single item to delete by id from mongoDB in nextjs app

I'm making a todo app in nextjs to practice, and I am having a hard time getting single todos to delete from the database using the deleteOne function.
Here is the call from the front end:
async function deleteTodo(id) {
await fetch(`/api/todos/${id}`, {
method: "DELETE",
});
setTodosList(todosList.filter((todo) => todo._id !== id));
}
and here is the handling of the DELETE method:
async function handler(req, res) {
let client;
try {
client = await connectDatabase();
} catch (error) {
res
.status(500)
.json({ message: error.message || "Error connecting to MongoDB." });
return;
}
if (req.method === "DELETE") {
const { id } = req.query;
console.log(id);
if (!id || id.trim() === "") {
res
.status(500)
.json({ message: "A todo id was not sent with the request." });
client.close();
return;
}
try {
let result;
let allTodos;
result = await deleteTodo("todos", id);
allTodos = await getAllTodos("todos");
res.status(201).json({
message: `Todo ${id} successfully removed!`,
todos: allTodos,
});
} catch (error) {
res
.status(500)
.json({ message: error.message || "Unable to delete todo." });
}
}
client.close();
}
and the deleteTodo helper function it calls:
export async function deleteTodo(collection, id) {
const client = await connectDatabase();
const db = client.db();
const result = await db.collection(collection).deleteOne({ _id: id });
return result;
}
I can get it to delete the first item in the array of todos if I pass deleteOne an empty object, but when I try to specify the id by using { _id: id } it does not delete.
Can anyone see what is happening to cause this? Thanks.
I think your id passed from front-end has string type. Since _id has ObjectId type, you need to convert id string to ObjectId.
Install:
npm i bson
Import in your deleteTodo:
import { ObjectId } from 'bson';
and try to change, in deleteTodo
const result = await db.collection(collection).deleteOne({ _id: ObjectId(id) });

GraphQL rate limit on mutations

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.

Output results to the user

I'm writing a telegram bot. There is a piece of working code that responds to messages from the user, searches for key word matching database and sends the result to user. The problem is that the sample result gets into the console, how to send it to the user? Please, help
bot.on('message', (ctx) => {
const text = ctx.text
const log = sequelize.query("SELECT book FROM books t WHERE (t.*)::text LIKE '%"+ text +"%'") .then( (result) => {
console.log(result,log)
}) .catch( (err) => {
console.log(err);
for (const result of results) {
ctx.reply(result.book);
}
})
})
Based on sendMessage api and data in message Your code should look like this:
const { QueryTypes } = sequelize;
bot.on('message', async (message) => {
const {text, chat} = message; // https://core.telegram.org/bots/api#message
const {id: chatId} = chat; // https://core.telegram.org/bots/api#chat
let response = '';
try {
const rows = await sequelize.query(
'SELECT book FROM books t WHERE (t.*)::text LIKE :searchText',
{
replacements: { searchText: `%${text}%` },
type: QueryTypes.SELECT,
}
);
console.log('ROWS:', rows);
if (rows.length) {
response = rows.map(row => row.book).join("\n");
}
else {
response = 'Book not found';
}
}
catch (error) {
console.error(error.message);
response = 'Unable to lookup';
}
finally {
if (response) {
bot.sendMessage(chatId, response);
}
}
})
Check manuals:
sendMessage
Message object
Chat object
Sequelize replacements

Check if document exists in collection with Mongoose Model

I want to to check if email already exists in 'users' collection:
I have this model:
const isEmailExists = async (value) => {
const res = await User.countDocuments({ email: value });
return res > 0;
}
const User = mongoose.model('User', {
email: {
type: String,
required: true,
validate(value) {
isEmailExists(value).then(res => {
if (res) {
throw new Error('Email already exists');
}
})
}
}
});
And I use post method with express router:
router
.route('/register')
.get((req, res) => {
res.sendFile(publicDirPath + '/auth/register.html');
})
.post(async (req, res) => {
const user = new User(req.body);
try {
const saveUser = await user.save();
res.send(saveUser);
} catch (error) {
res.send(error);
}
});
For some reason, it does not work and the user is been added anyway..
What am i doing wrong ?
If you want to check if one document with a certain entry/value exists you can do this :
function emailExists(value) {
User.findOne({email: value}).then((err, user) => !!user)
}

How to return a value from within activedirectory method

I've got a method in a class which does query an ActiveDirectory.
Therefore I'm using 'activedirectory2' npm package.
I successfully authenticated and successfully logged my result to console.
Now that I have instanciated my class and have tried to call the method, I'm not abled to get a non-empty result.
I tried it with getters/setters to make the _result value available after instaciating the class.
I tried to solve my issue with research on asynchronous calls, but obviously wasn't able to ask the right question.
class Activedirectory
var ActiveDirectory = require("activedirectory2");
class AuthenticateWithLDAP {
constructor(user, password){
this._result = [];
this.user = user;
this.password = password;
this.config = {
url: "ldaps://someldap",
baseDN: "somebasdn",
username: this.user,
password: this.password,
filter: 'somefilter',
}
this.ad = new ActiveDirectory(this.config);
}
//Auth Method
auth() {
var result = this._result;
this.config.entryParser = function(entry,raw,callback){
if(entry.hasOwnProperty('info')) {
result.push(entry.info);
this._result = result;
}
callback(entry);
}
this.ad.authenticate(config.username, config.password, (err,auth)=>{
if (err) {
//some error handling
}
if (auth) {
this.ad.find(config,async (err, userDetails) => {
var result = this._result;
{
if (err) {
//some error handling
}
if(!userDetails) {
console.log("No users found.");
} else {
this._result = result[0]; //I want this result!
console.log('result: ', this._result);
return await this._result;
}
}
})
} else {
console.log("Authentication failed!");
}
});
}
//getter/setter
get result(){
return this._result;
}
set result(value) {
this._result.push(value);
}
}
module.exports = AuthenticateWithLDAP;
route module
const express = require('express');
const AuthwithLDAP = require('AuthenticateWithLDAP');
const router = express.Router();
router.post('/', async (req,res,next) => {
let x = async ()=> {
authwithldap = new AuthwithLDAP(req.body.user,req.body.password);
return await authwithldap.auth();
}
x().then((res)=>{
console.log('res: ', res); //always []
})
})
I expected to be able to use the _result value of AuthenticateWithLDAP class in my router.post method handler.
Actually i only get [] (empty array) in router.post.
Could you please tell me how to alter the value _result in a way, so that the instance of the class knows it and can use it outside the class itself.
Thank you very much.
Micha
I am not 100% sure but I think this should work.
In your code you cant return the result because the return is in a callback.
There are to ways to fix that.
Pass a callback to the auth() method (This is bad since callbacks suck)
Return a promise and that resolves to the result
I've decided to go for promises.
var ActiveDirectory = require("activedirectory2");
class AuthenticateWithLDAP {
constructor(user, password){
this._result = [];
this.user = user;
this.password = password;
this.config = {
url: "ldaps://someldap",
baseDN: "somebasdn",
username: this.user,
password: this.password,
filter: 'somefilter',
}
this.ad = new ActiveDirectory(this.config);
}
//Auth Method
auth() {
return new Promise((resolve, reject) => {
this.ad.authenticate(config.username, config.password, (err,auth)=>{
if (err) {
//Call reject here
}
if (auth) {
this.ad.find(config,async (err, userDetails) => {
var result = this._result;
{
if (err) {
//some error handling
}
if(!userDetails) {
console.log("No users found.");
} else {
this._result = result[0]; //I want this result!
resolve(await this._result);
}
}
})
} else {
console.log("Authentication failed!");
}
});
});
}
}
module.exports = AuthenticateWithLDAP;
const express = require('express');
const AuthwithLDAP = require('AuthenticateWithLDAP');
const router = express.Router();
router.post('/', async (req,res,next) => {
/* This code can be simplifed
let x = async () => {
authwithldap = new AuthwithLDAP(req.body.user,req.body.password);
return await authwithldap.auth();
}
x().then((res)=>{
console.log('res: ', res); //always []
})
*/
(async () => {
authwithldap = new AuthwithLDAP(req.body.user,req.body.password);
var res = await authwithldap.auth();
console.log('res: ', res);
})();
})
Could you try to add syntax "await" like this?
await x().then((res)=>{
console.log('res: ', res); //always []
})
As your "x" method is in async mode, maybe you have to wait for the Promise to be resolved...

Categories