NodeJs api with mongoose any request go to another collection efficient - mongodb

I'm write nodeJs api for app with users and I want for each user to use another mongo collection.
I recognize each user with the URL address in the params fields.
everything is work fine.
But when I go to collection dynamically it's very slow.
any one idea how to do this faster?
thanks in advance ;)
app.js
this code do req in 2.5 seconds
POST /login 200 2487.531 ms - 206
app.use("/:businessUrl", (req, res, next) => {
console.log(req.params.businessUrl);
mongoose
.connect(process.env.MONGO_URI + `${req.params.businessUrl}retryWrites=true&w=majority`,)
.then((result) => {
console.log("DB Connected");
next();
})
.catch((err) => {
return next(err);
});
});
and this code when the collection is hard coded
do the same req in 0.5 seconds
POST /login 200 461.829 ms - 206
mongoose .connect(process.env.MONGO_URI + `businessUrl?retryWrites=true&w=majority`)
.then((result) => {
console.log("DB Connected");
})
.catch((err) => {});

The latency is coming because you are creating a connection everytime the API is being hit.
As I can see from implementation, There is same server that you are using just switching the database.
So, You can use the useDB method provided by mongoose. It also has an option to maintain cache for the connection object for each DB.
Official Docs: https://mongoosejs.com/docs/api/connection.html#connection_Connection-useDb
Using above approach will only create connection to the database when the API is being hit first time but will resolve it from cache if we are hitting it after first time.

Related

Why use useMutation in React Query?

I am new to react query.
I found out that using useQuery can reduce requests by caching.
But it's hard to understand why I use useMutation.
axios.post('/user', { name, ... })
.then(res => console.log(res))
.catch(err => console.log(err);
const { mutate, isLoading, ... } = useMutation(fetcher, {
onSuccess: (res) => {
console.log(res);
},
onError: (err) => {
console.log(err);
}
});
Both codes handle successful requests and errors.
Isn't queryClient.invalidateQueries('queryKey'); also covered by axios then() function?
What's the difference between the two?
It's a difference in what happens to the backend state. In a query the intention is that you're requesting a particular dataset from some source. The request does not change any backend state, and any re-requests for the data will also not cause a change to backend state.
In a mutation the intention is to create some change in the backend state. (e.g. creating a new record in a database, or updating an existing record).
It's the equivalent of a read (query) vs write (mutation) operation
At least useMutations provides a lot of useful stuff like loading state, error, etc. under the hood.

How to create a simple retrieve API after the connection has been done?

I am very new to MongoDB and Nodejs and I would like to know how to create a very simple find all the records from a collection.
What I have done so far and it is listening to port 5000 in the console log:
const express = require('express')
const BodyParser = require("body-parser");
const {MongoClient} = require('mongodb')
const port = 5000;
const app = express()
app.use(BodyParser.json());
app.use(BodyParser.urlencoded({ extended: true }));
var db;
const uri = "mongodb+srv://user1:mypassword#cluster0.2sgiu.mongodb.net/ecommerce?retryWrites=true&w=majority";
app.listen(port,() => {
MongoClient.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true}, (err, database) => {
if (err) {
console.log("Error occurred connecting to MongoDB...")
}
console.log(`Listening to part ${port}...`)
});
})
How do I proceed from here to create an API to retrieve all records from a Books collection after the connection has been done? Thanks
You should first save the database object that is returned to you by the callback function of connect (let's called that db).
Then, you can use that object to access your collections like "Books" in this example:
db.Books
To get all the documents inside a collection you can use the find method with an empty object as the argument.
const books = db.Books.find({});
If you want to tie MongoDB queries to your Express app, you should a create routes in which, you can respond the request with data that you fetched. Considering that this data is going to be publicly available.
app.get('/books', (req, res) => {
const books = db.Books.find({});
res.status(200).send({ books });
});
You can now make a GET request to localhost:5000/books and it should respond to you back with the contents of the Books collection. Either use your browser or curl to make the request.
$ curl localhost:5000/books

Mongoose/Express - problems using findById()

I have a database of activities in MongoDB, had all the basic CRUD operations working fine but now at the point in developing the front end of the app where I need to do a GET request for a single activity in the database. I have working PUT and DELETE requests for single activities but for some reason the GET one just isn't playing ball - it's returning an array of objects rather than a single object with that ID.
I'm currently using Postman to make the requests while I iron this problem out. Mongoose version is 5.12.13.
router.get('/:id', async (req, res) => {
try {
const activity = await Activities.findById(req.params.id)
res.json(activity).send()
} catch (error) {
res.send(error.message)
}
})
Then making a request using Postman to http://localhost:5000/api/activities?id=60968e3369052d084cb6abbf (the id here is just one I've copied & pasted from an entry in the database for the purposes of troubleshooting)
I'm really stumped by this because I can't understand why it's not working! The response I get in Postman is an array of objects, like I said, which seems to be the entire contents of the database rather than just one with the queried ID...
Try calling exec on your findById, findById returns a query, you need to call exec to execute your query.
Without the call to the exec function, your 'activity' variable is a mongoose query object.
router.get('/:id', async (req, res) => {
try {
const activity = await Activities.findById(req.params.id).exec();
res.json(activity).send()
} catch (error) {
res.send(error.message)
}
});
Docs for findById
https://mongoosejs.com/docs/api.html#model_Model.findById
Edit:
As righty spotted by Dang, given your code is inspecting req.params the URL you're calling needs updating to:
http://localhost:5000/api/activities/60968e3369052d084cb6abbf

MongoDB requests very slow to return results

So, I only have a few documents in my Mongo DB. For example, I have this basic find request (see below) which takes 4 seconds to return a 1.12KB JSON, before the component re-render.
app.get('/mypath', (req, res) => {
MongoClient.connect(urlDb, (err, db) => {
let Mycoll = db.collection('Mycoll');
Mycoll.find({}).toArray( (err, data) => {
if (err) throw err;
else{
res.status(200).json(data);
}
})
db.close();
})
});
Sometimes for that same component to re-render, with the same request, it takes 8 seconds (which equals an eternity for an Internet user).
Is it supposed to take this long ? I can imagine a user of my app starting to think ("well, that doesn't work") and close it right before the results show.
Is there anything you could point me to to optimize the performance ? Any tool you would recommend to analyze what exactly causes this bottleneck ? Or anything I did wrong ?
At this stage, I don't incriminate React/Redux, because with no DB requests involved, my other components render fast.

Express JS routing based on the user names

I am working on a express js project.I have got all my basic routing set up working perfectly. Usually when I want to search a record based on id I do this:
router.route('/sensors_home/:sensor_id')
.get(function (req, res) {
Sensor.findById(req.params.sensor_id,function(err, sensorInfo) {
if (err)
res.send(err);
res.send(sensorInfo);
});
});
This allows me to retrieve the data when I do http://localhost:4000/sesnors_home/45000cbsfdhjbnabfbajhdb
(45000cbsfdhjbnabfbajhdb = Object id from the MongoDB )
Now my goal is to have several users to my application. I have my mongoose schema set up and the mongoDB looks like this :
Here is the issue: I wanna retrieve data corresponding to John Peterson based on his _id that is "John".Instead of doing this http://localhost:4000/sesnors_home/45000cbsfdhjbnabfbajhdb I wanna do something like this http://localhost:4000/sesnors_home/John and retrieve all the data specific to John. I tried various methods but still stuck with this issue. I tried using req.params._id and also some Mongodb queries on the User Collection but still no luck. Please suggest some ideas.
Thanks!
UPDATE:
I tried using the following code :
router.route('/sensors_home/:id')
.get(function (req, res) {
res.send(_id.toString());
User.findOne({_id: req.params._id} ,function(err, sensorInfo) {
if (err)
res.send(err);
res.send(sensorInfo);
});
});
This gives me the following error :
ReferenceError: _id is not defined
Have you tried the following?
router.route('/sensors_home/:_id')
.get(function (req, res) {
Sensor.findOne({_id: req.params._id},function(err, sensorInfo) {
if (err)
res.send(err);
res.send(sensorInfo);
});
});