Why use useMutation in React Query? - 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.

Related

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

NodeJs api with mongoose any request go to another collection efficient

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.

Express - return certain documents with named route parameters using axios

I'm having trouble communicating between the frontend and backend for a selected GET request.
I am using a React frontend with an express/mongoose setup out in the backend.
In the frontend, I do a GET call using axios for:
axios.get('/api/orders/', {
params : {
name: this.props.user.name // user name can be Bob
}
})
And in the backend I'm having a hard time understanding the correct method I would need to do to query the database (example below doesn't work). I found stuff with .select but even then I still can't get it to work:
router.get('/orders', function(req, res) {
Order.find({}).select(req.params).then(function (order) {
res.send(req.params);
})
});
I also tried doing this to see if I can even get the params to send properly and to no demise:
router.get('/orders/:name', function(req, res) {
res.send('client sent :',req.query.name);
});
The orders document model holds objects that house an ordered array and a name (type: String) attached to the object. The Mongoose scheme for the order:
const orderScheme = new Schema({
name : { type : String },
orders : { type : Array}
});
In my MongoDB, I can see all the "Master Orders" send back. Each master order has the name of who submitted it, plus all the orders within (there can be a ton of orders).
What I'm trying to exactly do is pull up all orders that have a certain name. So if I search "TestAccount", I'll get all of bob's orders. I've included an image below:
Any pointers?
Client-side:
axios.get('/api/orders/' + this.props.user.name)
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
You need to handle the Promise when resolved/rejected.
Server-side:
router.get('/orders/:name', function(req, res) {
return Order.find({name: req.params.name}).then(function(orders) {
// return orders when resolved
res.send(orders);
})
.catch(function (error) {
// handle error
console.log(error);
})
});
You did not specify a named route parameter in your route path.
You also aren't accessing the name property by using req.params only.
You should use Model.find() conditions parameter to specify which document[s] you're trying to find. Query.prototype.select() is for filtering document fields.

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.

Ionic 2 MEAN Application doesn't return updated data on get request

I've been having this weird issue with an application I'm building. Essentially a function is invoked I want to read in a user's current game statistics -Wins, losses, draws etc - I do this using a service which creates an observable and consumes data from my rest api. On first call of this method the data read in is the most current up to date version but after this point I update the document for the user in the database and then when I execute the function again it reads in the original document before the update. However when I check the database the document has in face been updated.
Here is my provider function for consuming the data.
getUser(id) {
if (this.data) {
return Promise.resolve(this.data);
}
return new Promise(resolve => {
this.http.get('https://pitchlife-hearts.herokuapp.com/api/users/' + id)
.map(res => res.json())
.subscribe(data => {
this.data = data;
resolve(this.data);
});
});
}
Here is the call I make in my function.
play(challenger, opponent) {
this.userService.getUser(_id).then((data) => {
this.challenger_account = {
_id: data._id,
points: data.maroon_points,
wins: data.wins,
draws: data.draws,
losses: data.losses
};
Here is my update call.
this.userService.updateUser(this.challenger_account);
Here is my api endpoint call as well although this does work every time I update the data.
app.post('/api/users/update', function (req, res) {
// Update a user
var options = {};
User.update({_id : req.body._id }, {
maroon_points: req.body.points,
wins: req.body.wins,
draws: req.body.draws,
losses: req.body.losses
}, options,
function (err, user) {
if (err)
res.send(err);
res.json(user);
});
});
Any help with this would be hugely appreciated as this is driving me crazy.
When are you updating the this.data property that the getUser(id) { ... } method uses?
Because the first time the getUser(id) {...} method is executed, this.data is null and because of that the http request is made. But after that, the value of this.data is always returned, but if you don't update it manually, it'll be always the first value it was set to.