how to correctly get (axios) by UUID , ReactJs NodeJs - mysql

I would like to explain my problem of the day.
currently i am logging in,
I am in my profile, and here I would like to display my name.
the following code works correctly, only it shows me all the use registered in my database.
and I would only like to be able to display the correct name which corresponds to the UID in my database
How can I fix this issue?
that is my get and return
class Profile extends Component {
constructor(props) {
super(props);
this.state = {
data:[]
};
}
getRandom = async () => {
const res = await axios.get(
"https://joke.fr/api/profil"
);
this.setState({ data: res.data })
}
componentDidMount() {
this.getRandom()
}
render() {
return (
<div>
{this.state.data.map(data => <p>{data.name}</p>)}
</div>
)
}
}
export default Profile;
that is my route is bdd
app.get('/api/profil', (req, res) => {
connection.query('SELECT * from profil' , (err, results) => {
if (err) {
console.log(err);
return res.status(500).send('Erreur lors de la récupération des employés');
} else {
console.log(results);
return res.json(results);
}
});
});
and last one is my BDD schéma.
{
"id": 62,
"name": "neff",
"uid": "dycjibu96zgmzc0KpGAqxKiUsMu2"
}

You would need another parameter in your app.get. I suppose when user logged in to your app, you store their UID. If that's the case, you can use:
app.get('api/profil/:id', (req, res) => {
const userId = req.params.id
connection.query(`SELECT * from profil WHERE id = ${userId}` , (err, results) => {
if (err) {
console.log(err);
return res.status(500).send('Erreur lors de la récupération des employés');
} else {
console.log(results);
return res.json(results);
}
});
})
But I would recommend something like body-parser to sanitise your SQL request though.

Since you are logged in then probably you have the UUID or name in the browser saved in the local storage (this is the simplest approach). This means on your backend you should send a GET request to get 1 profile based on the UUID.
Server Side Code
app.get('/api/profil/:name', (req, res) => {
const { name } = req.params;
connection.query(`SELECT * from profil where name=${name}`, (err, results) => {
if (err) {
console.log(err);
return res.status(500).send('Erreur lors de la récupération des employés');
} else {
// This should be an object
console.log(results); // This should be an object like {"id": 62, "name": "authUser"}
return res.json(results);
}
});
});
Client Side Code
class Profile extends Component {
constructor(props) {
super(props);
this.state = {
userProfile: null
};
}
getUserProfile = async (userName) => {
// Get the profile by passing the id to the URL.
// Side note, you should handle errors here but for simplicity lets skip it.
const res = await axios.get(
`https://joke.fr/api/profil/${userName}`
);
// res.data should be an object like {"id": 62, "name": "authUser"}
this.setState({ userProfile: res.data });
}
componentDidMount() {
// You should have the id of the user after login
// Let me assume you stored it in localstorage
const user = localStorage.getItem("user");
if (user) {
const { id, name } = JSON.parse(user);
// You can skip the localstorage part if you store the user's details in a different way and jump here by passing the ID/name to this function
this.getUserProfile(name);
}
}
render() {
const { userProfile } = this.state;
return (
<div>
{userProfile ? userProfile.name : "No user name"}
</div>
)
}
}
export default Profile;

Related

Mongoose updating and fetching in the same request

I have the following mongoose "update" path:
app.put('/update', async (req, res) => {
const newTaskName = req.body.todoName
const newDays = req.body.days
const id = req.body.id
try {
await TodoModel.findById(id, async (err, updatedTodo) => {
updatedTodo.todoName = newTaskName
updatedTodo.daysToDo = newDays
await updatedTodo.save()
res.send("updated")
})
} catch(err) {
console.log(err)
}
})
Separately I have a path that returns all data from the Mongo table:
app.get('/read', async (req, res) => {
TodoModel.find({}, (err, result) => {
if (err) {
res.send(err)
}
res.send(result)
})
})
How can I both update and send back the full updated list within the response?
Separate question, not necessary to answer, but would be nice - perhaps this approach is all wrong? some background:
In my MERN app I am calling to add an item to a list and then want to immediately render the updated list as currently read from the database, since I don't want to assume the insertion was successful
I tried using some asynchronous workarounds with no luck
Fixed!
Upon further inspection of Mongoose documentation, I found that by using the findOneAndUpdate method instead of findById, I am able to utilize a callback that will return the updated item:
app.put('/update', async (req, res) => {
const id = req.body.id
let updateSet = req.body
delete updateSet.id
try {
ShoppingModel.findOneAndUpdate({ _id: id }, { $set: updateSet }, { new: true }, (err, doc) => {
if (err) return console.log(err)
res.send(doc)
})
} catch (err) {
console.log(err)
}
})

How could I pass JSON object array result to my api URL? (In REACT)

I have to fetch 2 api from backend, and try to get the result from this two. but, at the moment, the JSON result I get from the first API is object Array in JSON. I need to pass the id from first API(using setState) to second API for path variables. But when I do in my way, it fail to retrieve the data. Consider the code below:
componentDidMount(){
// console.log(loginEmail)
fetch(`http://localhost:9000/api/item/list`,)
.then((resp)=>{
resp.json().then((res)=>{
console.log(res.data);
// localStorage.setItem('id', res.data.user_info.id);
this.setState({data: res.data});
}
)
})
const id = this.state.data.id;
fetch(`http://localhost:9000/api/item/photo/view/${id}`,)
.then((resp)=>{
resp.json().then((res)=>{
console.log(res);
// localStorage.setItem('id', res.data.user_info.id);
this.setState({res});}
)
})
}
The problem is that fetch returns a Promise so, at the line
const id = this.state.data.id;
You do not have data populated yet.
You have to concatenate the two requests in a way like the following:
componentDidMount() {
fetch(`http://localhost:9000/api/item/list`)
.then((resp) => {
// return the id
})
.then((id) => {
fetch(`http://localhost:9000/api/item/photo/view/${id}`)
.then((resp) => {
// do what you need with the result
})
})
}
Fetch is asynchronous, which means javascript will
fetch data on the first call with no waiting, and continue
to the second fetch call where the id is not defined or Null.
In order to fix that you can use promises as follow
My code example
import React from "react";
class Home extends React.Component {
constructor() {
super();
this.state = {
res: [],
}
}
// http://jsonplaceholder.typicode.com/users
fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then((resp) => {
resp.json().then((res) => {
console.log(res);
// localStorage.setItem('id', res.data.user_info.id);
resolve(res);
}
)
})
})
}
async componentDidMount() {
let data = await this.fetchData("http://jsonplaceholder.typicode.com/users");
console.log("data :", data);
let id = data[0].id;
console.log("Id :", id);
let newData = await this.fetchData(`http://jsonplaceholder.typicode.com/users/${id}`);
this.setState({ res: newData });
}
render() {
return (
<div>
Call API
</div>
)
}
}
export default Home
Adapted on your code
fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then((resp) => {
resp.json().then((res) => {
console.log(res.data);
// localStorage.setItem('id', res.data.user_info.id);
resolve(res.data);
}
)
})
})
}
async componentDidMount() {
// console.log(loginEmail)
let data = await this.fetchData("http://localhost:9000/api/item/list");
let id = data.id;
let newData = await this.fetchData(`http://localhost:9000/api/item/photo/view/${id}`);
this.setState({ res: newData });
}
You need to make sure that each id gets its relevant results.
async componentDidMount() {
await fetch(`http://localhost:9000/api/item/list`)
.then(async (resp) => {
let req_ = resp.map((item)=>{
return await fetch(`http://localhost:9000/api/item/photo/view/${item.id}`)
})
let result = Promise.all(req_)
console.log(result)
})
}

Convert MySQL update query into sequelize query

UPDATE `users` SET tempToken=tempToken-"5" WHERE `id`="1"
How can I write this query into sequelize query.
For an async function, this is how you would do it, assuming you've set up your User model:
myFunction: async (req, res) => {
var tempToken = req.body.tempToken // Put whatever your data source is here for tempToken
var newValue = tempToken - 5
try {
await User.update({
tempToken: newValue
},
{
where: [{
id: 1
}]
})
res.status(200).send();
}
catch (error) {
res.status(500).send(error);
}
}
or
myFunction: async (req, res) => {
try {
const user = User.findOne({
where: {
id: 1
}
})
await user.update({
tempToken: user.tempToken - 5
})
res.status(200).send();
}
catch (error) {
res.status(500).send(error);
}
}
Also, don't forget to 'require' the user model in the .js file that you use this function in.

React Native : render a fetched data structure

I am new to Javascript (NodeJS & JSON data structure) and React native, and I am trying to display some datas on the iOS screen test (react native). I did my best to understand but I am stuck.
I made a GET route on my Express app at /places on localhost:3000 :
router.get('/places', (req, res) => {
MongoClient.connect(url, function (err, db) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
console.log('Connection established to', url);
var colPlaces = db.collection('places');
colPlaces.find().toArray(function (err,result) {
if (err) {
res.send('error!');
} else if (result.length) {
res.send(result);
} else {
res.send('No entries');
}
})
db.close();
}});
})
It displays a data structure on my browser (seems to be an Array of JSON objects ?)
[
{"_id":"5894fdd694f5d015dc0962bc","name":"The good bar","city":"London"},
{"_id":"5894fdd694f5d015dc0962bd","name":"Alpha bar","city":"Paris"}
]
I am then trying to render it on my native react project :
constructor(props) {
super(props);
var datas = async function getDatas() {
try {
let response = await fetch('http://localhost:3000/places');
let responseJson = await response.json();
return responseJson;
} catch(error) {
console.error(error); }
}
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(datas())
};
}
render() {
return (
<View style={{flex: 1, paddingTop: 22}}>
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData}</Text>}
/>
</View>
);
}
But all I got is two "0" on my screen.
Can someone help me to find out what is wrong ?
What is/are,
* "result" variable structure ? seems to be an array of JS objects.
* "response" and "responseJSON" variables ?
* "datas()" and dataSource type
Should I parse something ? I am a bit confuse. Thank you.
First, "data" is already plural, there is no "datas". :) Now back to your question, getData is async function, so you cannot just call getData() and expect it to return data immediately. In the constructor, set dataSource to empty list, then:
async function getData() {
try {
let response = await fetch('http://localhost:3000/places');
return response.json(); // this call is not async
} catch(error) {
console.error(error);
}
}
componentDidMount() {
let data = await this.getData();
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.setState({dataSource: ds.cloneWithRows(data)});
}

How to delete message in all users using socket.io?

I am using socket.io and mysql (node server)
But I am not successful in delete function.
Here's what I have and what I've tried so far
io.on('connection', (socket) => {
connection.query("SELECT * FROM `messages`", (err, data) => {
for(let x in data) socket.emit('message', { id: data[x].message_id, text: data[x].message })
})
socket.on('disconnect', () => {
// console.log('user disconnected');
})
socket.on('add-message', (message) => {
addMessage(message, (res) => {
if(res) io.emit('message', { type: 'new-message', text: message});
})
});
socket.on('delete-message', (id) => {
connection.query("DELETE FROM `messages` WHERE `message_id` = '"+ id +"'");
io.emit('message', { type: 'delete-message', id: id }) // broadcast that something has changed
})
})
Angular2 service
import { Subject } from 'rxjs/Subject'
import { Observable } from 'rxjs/Observable'
import * as io from 'socket.io-client'
export class ChatService {
private url = 'http://localhost:5000'
private socket;
sendMessage(message) {
this.socket.emit('add-message', message);
}
getMessages() {
let observable = new Observable(observer => {
this.socket = io(this.url);
this.socket.on('message', (data) => {
observer.next(data);
});
return () => {
this.socket.disconnect();
};
})
return observable;
}
deleteMessage(id) {
this.socket.emit('delete-message', id);
}
}
Component
export class AppComponent implements OnInit, OnDestroy {
messages = []
connection;
message: any;
constructor(private chatService: ChatService){ }
sendMessage(): void {
this.chatService.sendMessage(this.message);
this.message = '';
}
ngOnInit() {
this.connection = this.chatService.getMessages().subscribe(message => {
this.messages.push(message);
})
}
ngOnDestroy() {
this.connection.unsubscribe();
}
deleteData(id): void {
for(var i = 0; i < this.messages.length; i++) {
if(this.messages[i].id == id) {
this.messages.splice(i, 1)
this.chatService.deleteMessage(id)
break;
}
}
}
}
Problem of what I have tried:
For deleteData(),
The user who clicked the delete button will have the desired view. But for other users, they must refresh for updated data.
Any help would be appreciated. Thanks.
First, keep in mind that you need to store all of your data into the array messages.
The challenging part is the message_id. Since you can't put a value on it. Assuming that it has an auto_increment. We need to add another table column which will have a unique value.
For my example, I will use message_identifier
The table will have (message_id, message_content, message_identifier)
To keep this short. message_identifier will just have time that converted to milliseconds(I believe). You must create a method that will make it completely different.
On your SERVER
Getting previous messages
connection.query("SELECT * FROM `messages`", (err, data) => {
for(let x in data) socket.emit('message', { type: 'get-messages', message: data[x].message, identifier: data[x].identifier })
}
Adding message
socket.on('add-message', function(message, identifier) {
connection.query("INSERT INTO `messages` (`message_content`, `message_identifier`) VALUES ('"+ message +"', '"+ identifier +"')", (err) => {
if(!err) io.emit('message', { type: 'new-message', message: message, identifier: identifier })
})
})
Deleting message
socket.on('delete-message', function(identifier) {
connection.query("DELETE FROM `messages` WHERE `message_identifier` = '"+ identifier +"'", (err) => {
if(!err) io.emit('message', { type: 'delete-message', identifier: identifier })
});
})
The logic will be on the component. You just need to listen for 'message' and identify through the type that request is passing.
So, here it goes:
Importing socket.io and observable and declaring socket on your component.
import * as io from 'socket.io-client'
import { Observable } from 'rxjs/Observable'
private socket = io(/* url of server */); // inside AppComponent
On your class AppComponent. You need to listen to 'message'
let data$ = new Observable(observer => {
this.socket.on('message', (data) => {
if(data.type == 'get-message' || data.type == 'new-message') {
observer.next({ message: data.message, identifier: data.identifier })
} else if(data.type == 'delete-message') {
for(let i = 0; i < this.messages.length; i++){
if(parseInt(this.messages[i].identifier) == data.identifier){
this.messages.splice(i, 1);
break;
}
}
}
console.log(data)
})
})
data$.subscribe(value => {
this.messages.push(value);
})
You can put this on ngOnInit or constructor. I believe it should work either of this two.
On your SERVICE
Just remove getMessages since we're handling it on component.
Hope it helps. Cheers!
You are sending a message from the client to your nodejs server to delete the message. What you are forgetting at the server side however, is to update al the other clients that something has changed. In your 'socket.on("delete-message")', you should also be sending a message to all connected users to notify them, something has changed. You can do that similarly to the add message:
io.emit('message', { type: 'delete-message', id: id});
Btw: Checkout ngrx/store. It's a Redux implementation for angular 2. If you are working with ngrx/store you define actions. Actions are meant to update the client side state. If you were using this, you could just define an action 'DELETE_MESSAGE' and send this action through your socket from server to client. The client would just dispatch this action to ngrx and your UI would update nicely :).