collection.find({}) doesnt work after many tries - javascript

I am building an api with express and mongoose and im usingdb.collection(collection).find({}) expecting that i get all of my docs back (3 test docs in total) as seen from tutorials. It doesnt give me any errors when im executing a req from postman and that confuses me as im geting nothing, not even an empty object or array as a response. I have tried different examples, from different tutorials but nothing works. Is the syntax wrong?
import express from 'express'
import './connection.js'
const router = express.Router
const db = mongoose.connection;
const dtb = db.useDb('main').collection('products')
router.get('/true', async(req, res) => {
try {
const products = await dtb.find({})
res.send(products).status(200)
} catch (err) {
console.log(err)
res.sendStatus(500)
}
})

So, after lookig again and again at my code I realized that the route /true was taken as a param by express as i have another route for app.get('/:_id', getItem).
After changing the route to /all/true parsing the docs into an array and after some debugging, my getAll function looks like this and finally works :
export const getAll = app.get('/all/true', async(req, res) => {
const products = await dtb.find({}).toArray().catch(console.error())
res.send(products)
})

Related

detect a request using NodeJS without express or accessing the request object outside an express middleware [duplicate]

This question already has answers here:
Access current req object everywhere in Node.js Express
(2 answers)
Closed 8 months ago.
This post was edited and submitted for review 8 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I have the following lines of code:
const express = require('express');
const app = express()
// ... defining the routes, app.get('/api/users', (req, res, next)=>{ }) ...etc
app.listen(3000, ()=> console.log('Listening on port 3000...'))
module.exports = app
I want to be able to read the request object outside an express middleware.
I have another file called mongoose_models.js, inside that file, I don't have the access to the express middleware arguments (req, res, next).
And the only option I have for reading the request body from that file is to import the app and somehow read the request Object.
NodeJs is event-driven, so there must be a way somehow to do so, for instance, inside the file mongoose_models.js I would have maybe something like this code:
// mongoose_models.js
// ... some code
const app = require('../app.js')
app.on('request', (req)=>{
// here I have the request
})
or maybe if express supports:
// mongoose_models.js
// ... some code
const { req } = require('express')
console.log(req.body) // ? maybe something like that ?
or maybe if express supports too:
// mongoose_models.js
// ... some code
const app = require('../app.js')
app.onRequest((req, res) => {
// here I have the access to the request object
})
Is there a way to reach the request object without having to be inside an express middleware in NodeJS?
edit:
Some of you asked me to provide the source code, unfortunately, I wanted to provide a stackblitz or code sandbox instance, but I didn't know how to set up the connections to the database.
Anyway, the following is the file structure of the sample project:
app.js file (full code):
const express = require('express')
const app = express()
const mongoose = require('mongoose')
const RoomModel = require('./mongoose_models')
app.use((req, res, next) => {
// this middleware is the "protect" middleware, it validates a JWT (JSON web token), decodes it, and then stores the user it finds to the req object:
// .... etc some code
// decode the JWT .. some code
// find the user in the DB const userDoc = await UserModel.findOne({ _id: decodedJWT.id )})
const userDoc = {
id: 'abc-123-edf-cds-123-321-qu5-eu4-dc9-182',
name: 'Murat',
// and some other fields ... etc
}
req.$loggedInUser = userDoc
})
app.get('/rooms', async(req, res, next) => {
const docs = await RoomModel.find({})
res.status(200).json({
message: 'here are all the rooms',
results: docs.length,
data: docs,
})
})
app.post('/rooms', async(req, res, next) => {
const doc = await RoomModel.create(req.body)
res.status(201).json({
message: 'the new room which got created:',
data: doc,
})
})
// connecting to the database:
mongoose.connect(
'mongodb+srv://USERNAME:PASSWORD#YOUR_CLUSTER.mongodb.net/?retryWrites=true&w=majority'
)
// starting the HTTP service:
app.listen(3000, () => console.log('app listening on port 3000...'))
mongoose_models.js file (full code):
const mongoose = require('mongoose')
const roomSchema = new mongoose.Schema({
name: String,
by: mongoose.Schema.ObjectId,
})
roomSchema.pre('save', function(next) {
// Here I want to make the by field be the req.$loggedInUser.id but I can't because I have no way to read the request object
const doc = this
// doc.by = req.$loggedInUser.id // < ----- 👈👈👈 HERE, I can't reach the req object
next()
})
const RoomModel = mongoose.model('Room', roomSchema, 'rooms')
module.exports = RoomModel
NodeJS is event driven, so there must be a way somehow to do so, for
instance, inside the file mongoose_models.js I would have maybe
something like this code:
// mongoose_models.js
// ... some code
const app = require('../app.js')
app.on('request', (req)=>{
// here I have the request
})
This approach is, essentially, middleware. So write is as middleware.
const myMiddleware = (req, res, next) => {
// here you have the request
next(); // go to next middleware
}
module.exports = myMiddleware
Attaching something to listen for requests is done with use (for non-method specific functions) and post, get, etc. There is no on method or onRequest method.
// mongoose_models.js
// ... some code
const { req } = require('express')
console.log(req.body) // ? maybe something like that ?
The request object doesn't exist until the client makes a request to the server.
You get a new request object each time a request is made.
The server might be handling multiple requests at the same time.
So no, you can't do anything like that.
Is there a way to reach the request object without having to be inside an express middleware in NodeJS?
No.

What is this error?: TypeError: Cannot read property '0' of undefined

While trying to build user authentification using mongodb and express I came across an error. The error basically happens every time I click submit on the website. That's the first problem, the second is after I click submit the page just keeps loading and never changes as if its stuck or trapped in an infinite loop. I tried deleting everything in the database and starting over but that didn't work. A little advice would be appreciated.
The error:
app: authRouter {
app: authRouter acknowledged: true,
app: authRouter insertedId: new ObjectId("613b5afd2139aeac87bd9682")
app: authRouter } +0ms
app: authRouter TypeError: Cannot read property '0' of undefined
app: authRouter at addUser (C:\Users\Yanki XXIV\Desktop\pluralsight\src\routers\authRouter.js:24:30)
app: authRouter at processTicksAndRejections (internal/process/task_queues.js:95:5) +19ms
authRouter.js:
const express = require('express');
const debug = require('debug')('app: authRouter');
const { MongoClient } = require('mongodb');
const authRouter = express.Router();
authRouter.route('/signUp').post((req, res) => {
const {username, password} = req.body;
const url =
'mongodb+srv://Yoshi:Yumcmaster1#cluster0.atic5.mongodb.net?retryWrites=true&w=majority'
const dbName = 'testdb';
(async function addUser(){
let client
try {
let client = await MongoClient.connect(url);
const db = client.db(dbName);
const user = {username, password};
const results = await db.collection('users').insertOne(user);
debug(results);
req.login(results.ops[0], ()=> {
res.redirect('/auth/profile');
});
} catch (error) {
debug(error)
}
client.close();
}());
});
authRouter.route('/profile').get((req, res) => {
res.json(req.user);
})
module.exports = authRouter;
I certainly don't know what your trying to do because I'm not so good at mongodb but I found a rather intresting thing in passport js docs and stackoverflow
Note: passport.authenticate() middleware invokes req.login() automatically. This function is primarily used when users sign up, during which req.login() can be invoked to automatically log in the newly registered user.
Check version of MongoDB Node.js Driver with command npm list mongodb. If it is version 4 then you can not access result.ops. In version 4 insertOne returns insertOneResult that have only 2 properties: acknowledged and insertedId.
NodeJS + MongoDB: insertOne() - get the inserted document from result.ops
http://www.passportjs.org/docs/login/

ReferenceError when using MongoDB Collection variable in external resolver file that was imported via mergeResolvers

This is a totally reduced example to better explain the issue! So when I use the resolver Query getAllUsers, the MongoDB Collection Users is not available in the external resolver file user.js. So when I send that query I get:
ReferenceError: Users is not defined
That's a correct behaviour. But I do not want to include all the resolvers in my index.js, because I have a better modularization in this way. So I have all my typedefs and resolvers in external files like this.
Current file structure
index.js
/graphql
/typdef
user.graphql
/resolver
user.js
The user.graphql schema is correctly working. It is just the user.js that is producing the error when I execute the query with the not available Users variable, as already said.
Here the index.js and user.js.
index.js
import express from 'express'
import cors from 'cors'
const app = express()
app.use(cors())
import bodyParser from 'body-parser'
import {graphqlExpress, graphiqlExpress} from 'graphql-server-express'
import {makeExecutableSchema} from 'graphql-tools'
import {fileLoader, mergeTypes, mergeResolvers} from 'merge-graphql-schemas';
import {writeFileSync} from 'fs'
const typeDefs = mergeTypes(fileLoader(`${__dirname}/graphql/typedef/*.graphql`), { all: true })
writeFileSync(`${__dirname}/graphql/typedef.graphql`, typeDefs)
export const start = async () => {
try {
const MONGO_URL = 'mongodb://localhost:27017'
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect(MONGO_URL, function(err, client) {
console.log("Connected successfully to server");
const db = client.db('project');
const Users = db.collection('user')
});
const URL = 'http://localhost'
const homePath = '/graphql'
const PORT = 3001
app.use(
homePath,
bodyParser.json(),
graphqlExpress({schema})
)
app.use(homePath,
graphiqlExpress({
endpointURL: homePath
})
)
app.listen(PORT, () => {
console.log(`Visit ${URL}:${PORT}${homePath}`)
})
} catch (e) {
console.log(e)
}
}
user.js
export default {
Query: {
getAllUsers: async () => {
return (await Users.find({}).toArray()).map(prepare)
}
}
}
What is the best way to pass the MongoDB or the Users collection to the resolver files. Or is there an even better solution for this issue?
First of all, this is NOT a proper solution, because declaring global variables while outsourcing schema is a bad design at all. But it works out and maybe this way someone gets an idea about how to improve this fix.
So to solve the issue all I had to do is changing the variable from local const to global.
So in index.js const Users = db.collection('user') is rewritten by global.Users = db.collection('user').
Same for the user.js. Here return (await Users.find({}).toArray()).map(prepare) is rewritten by return (await global.Users.find({}).toArray()).map(prepare).

Node/Express - use API JSON response to (server-side) render the app

Preamble: I'm new to web dev so maybe this might be a very basic question for you vets.
I'm using MVC architecture pattern for this basic app. I've models (MongoDB), views (Express Handlebars), and controllers (functions that take in req, res, next and returns promises (.then > JSON is returned, .catch > error is returned). I'll be routing the paths reqs to their corresponding api endpoints in the controllers.
This makes sense (right?) when I'm purely working on API calls where JSON is the res. However, I also want to call these api endpoints > get their res.json > and use that to render my HTML using Handlebars. What is the best way to accomplish this? I can create same controllers and instead of resp being JSON, I can do render ("html view", res.json). But that seems like I'm repeating same code again just to change what to do with the response (return JSON or Render the JSON).
Hope I'm making sense, if not, do let me know. Please advise.
p.s. try to ELI5 things for me. (:
Edit:
//Model Example
const Schema = require('mongoose').Schema;
const testSchema = new Schema({
testText: { type: String, required: true },
});
const Test = mongoose.model('Test', testSchema);
module.exports = Test;
//Controller Example
const model = require('../models');
module.exports = {
getAll: function(req, res, next) {
model.Test.find(req.query)
.then((testItems) => {
!testItems.length
? res.status(404).json({ message: 'No Test Item Found' })
: res.status(200).json(testItems);
})
.catch((err) => next(err));
},
};
//Route Example
const router = require('express').Router(),
controller = require('../controllers');
router.get('/', controller.getAll);
module.exports = router;
I want the endpoints to return JSON and somehow manage whether to render (if the req comes from a browser) or stay with JSON (if called from Postman or an API web URL for example) without repeating the code. I'm trying to not create two endpoitns with 99% of the code being the same, the only difference being .then > res.status(200).json(testItems); vs .then > res.status(200).render('testPage', { testItems}).
For postman you could check the existence of postman-token in req.headers, then you could render accordingly, something like this:
req.headers['postman-token'] ? res.json({ /* json */ }) : render('view', {/ * json */});
If you want to go with checking postman token then you can use similar to method1.
if you want to check with query params in this case you can get json response or html even from browser for future use also and is not dependent on postman then use similar to method2 of the following example.
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
const port = 5000
app.get('/method1', (req, res) => {
const isJSONResp = req.headers['postman-token']
const resp = { status: "hello" }
if (isJSONResp) {
res.json(resp)
} else {
res.render('some.html', resp)
}
})
app.get('/method2', (req, res) => {
const params = req.params
const resp = { status: "hello" }
if (params.resp === 'json') {
res.json(resp)
} else {
res.render('some.html', resp)
}
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))

Axios get request keeps hitting 404

This is the get request:
this.props.userId contains the userId.
componentDidMount() {
axios.get('/api/auth/booked/' + this.props.userId)
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
}
This is the routes on my backend:
router.get('/booked:id', UserController.bookedClasses);
It's something to do with the '/booked:id'
Result:
GET http://localhost:3000/api/auth/booked/5bdb18071c8fb30d31969aef 404 (Not Found)
Nice and simple but for some odd reason, I can't get a response, I have all my system working apart from this route, can anyone spot anything that shouldn't be there?
Any feedback would be appreciated to help me and others!
This is my routes folder which holds all my routes:
const express = require('express');
const router = express.Router();
const UserController = require('../controllers/auth');
router.post('', UserController.createUser);
router.post('/login', UserController.login);
router.post('/bookclass', UserController.bookClass);
router.get('/:id', UserController.getUser);
router.get('/booked:id', UserController.bookedClasses);
module.exports = router;
Router params must be specified in the path of the route. Example:
'/some/route/:param'
or with multiple params:
'/some/route/:param/:anotherParam'
In your example:
router.get('/booked:id', UserController.bookedClasses);
should be (check the extra / in the path):
router.get('/booked/:id', UserController.bookedClasses);

Categories

Resources