Multer image upload patch request - node.js

I have a code to upload a form with some field name & a single image in nodejs using multer. Everything works fine when a new file is being uploaded on the POST request. Also, the PATCH request for changing the image is working fine. But, the issue goes that if I need to only change the image, not the service_name, it nullifies the field instead of retaining the previous name provided while a new POST was created.
PATCH REQUEST
exports.editService = async (req, res) => {
const { id } = req.params;
const { service_name } = req.body;
const updates = {};
if (req.body) {
updates.service_name = service_name;
}
if (req.file) {
const service_pic = req.file.filename;
updates.service_pic = service_pic;
}
try {
const updated_data = await Services.findOneAndUpdate({ _id: id }, {
$set: updates
},
{
new: true
}
);
if (!updated_data) {
res.status(404).json({ message: "Data does not exist" });
return;
}
res.status(200).json({ message: "Data updated", result: updated_data });
} catch (error) {
res.status(500).json({ message: "Internal server error", error });
}
}
In the PATCH/PUT request, the service_name is always null.
Postman result:
{
"message": "Data updated",
"result": {
"_id": "5f3648f8aefb2978e8f82d94",
"service_name": null,
"service_pic": "service_pic-1597396108999TIME-CLOCK-service.png",
"createdAt": "2020-08-14T08:19:04.013Z",
"updatedAt": "2020-08-14T09:08:29.012Z",
"__v": 0
}
}
Not sure where I am handling it wrong. Any help to rectify this is appreciated.

Related

Make a POST request and fetch posted data back to client

I need assistance in fetching data back to client as soon as it is posted to the database without reloading the page. The structure I have at present only shows the posts on page reload. Below are my codes.
const [pst, setPst] = useState([]);
const handleSubmit = async (e) => {
e.preventDefault();
const v2 = PST_REGEX.test(pst);
if (!v2) {
// setErrMsg("Invalid Entry");
return;
}
try {
const response = await axios
.post(DASHBOARD_URL, JSON.stringify({ pst }), {
headers: { "Content-Type": "application/json" },
withCredentials: true,
})
} catch (err) {
console.log(err)
}
};
Post Controller
const handleNewPost = async (req, res) => {
const { pst } = req.body;
if (!pst) return res.status(400).json({ message: "Field cannot be blank" });
try {
//create and store the new post
const result = await Userpost.create({
post: pst,
});
console.log(result);
res.status(201).json({ success: `New post ${pst} created!` });
} catch (err) {
res.status(500).json({ message: err.message });
}
};
There are some ways from which you can achieve your solution.
Method 1:
You can return newly created data from backend as success response. Lets assume you got response as follow:
{
"message": "Data created Successfully",
"status" : "201",
"data": [{
"id": "1234",
"title": "Blog title",
"description" : "Blog description"
}]
}
Then you can simply add response to you previous state as:
setPst([...pst, ...message.data]) // message.data is response from your endpoint
Method 2:
You can use socket io for real time experience: https://socket.io/

Using React, NodeJS, and Postgres: Having trouble being able to delete and updating todos

I am creating simple todo app with postgre and react.
The server side the delete and update are defined as below.
app.put("/todos/:id", async (req, res) => {
try {
const { id } = req.params;
const { description } = req.body;
const updateTodo = await pool.query(
"update todo set description = $1 where todo_id = $2",
[description, id]
);
res.json("todo updated !!");
} catch (error) {
console.error(error.message);
}
});
// delete todo
app.delete("/todos/:id", async (req, res) => {
try {
const { id } = req.params;
const deleteTodo = await pool.query("delete from todo where todo_id = $1", [
id,
]);
res.json("todo deleted !!");
} catch (error) {
console.error(error.message);
}
});
On the front end (React) this is how I am calling the update and delete
const updateDescription = async () => {
try {
handleClose();
const body = { description };
const response = fetch(`http://localhost:3000/${todo.todo_id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
console.log(response);
} catch (error) {
console.log(error.message);
}
};
Delete todo is in the other component.
const deleteTodo = async (id) => {
try {
const deleteTodo = await fetch(`http://localhost:3000/${id}`, {
method: "DELETE ",
});
console.log(deleteTodo);
setTodods(todos.filter((todo) => todo.todo_id !== id));
} catch (error) {
console.log(error.message);
}
};
So when I am doing delete or put request its not updating it in the DB.
On the browser console I am getting this error.
Failed to execute 'fetch' on 'Window': 'DELETE ' is not a valid HTTP method.
Edited
Response {type: "cors", url: "http://localhost:3000/3", redirected: false, status: 404, ok: false, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 404
statusText: "Not Found"
type: "cors"
url: "http://localhost:3000/3"
__proto__: Response
For insert todo its working but for delete and put request its not updating in the database.
So can somebody tell me whats going wrong here ?
There is a space after DELETE, correct it should work properly. Even if its a simple todo App, its always good practice to create an enum or const when we are dealing with fixed string, i.e., we know the string would not change so that we can have consistency and skip over these kind of issues.
const METHOD = {
GET: "GET",
PUT: "PUT",
POST: "POST",
DELETE: "DELETE"
};

Microsoft Graph API outlook send attachments

How do you send attachments with the Microsoft graph outlook API? I understand everything for sending attachments up until the content bytes. The files that I need to send are a word document a pdf and a jpeg Is it asking me to turn the file into bytes, if so how would I do that? I am using node.js and I have the following code:
exports.send_mail = async function(req, res, next) {
let parms = { title: 'Inbox', active: { inbox: true } };
const accessToken = await authHelper.getAccessToken(req.cookies, res);
const userName = req.cookies.graph_user_name;
if (accessToken && userName) {
parms.user = userName;
// Initialize Graph client
const client = graph.Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
//read test.html
//so you have to wait for the file to read then send it
message = fs.readFileSync('views/test.html', 'utf8');
console.log(rawImage.data.toString('utf8'))
try {
mailMess ={
message:{
subject: 'This is a test',
body:{
ContentType: 'HTML',
Content: message
},
ToRecipients:[
{
EmailAddress:{
Address: 'name#email.com'
}
}
],
"attachments": [
{
"#odata.type": "#microsoft.graph.fileAttachment",
"name": "attachment.jpeg",
"contentBytes": "not sure what to put here"
}
]
}
}
//sendmail
const result = await client
.api('/me/sendmail')
.version('v1.0')
.post(mailMess);
res.status('202')
parms.messages = result.value;
res.redirect('/');
} catch (err) {
parms.message = 'Error retrieving messages';
parms.error = { status: `${err.code}: ${err.message}` };
parms.debug = JSON.stringify(err.body, null, 2);
res.render('error', parms);
}
} else {
// Redirect to home
res.redirect('/');
}
}
I found out that param takes the file encoded as base64

MEAN stack how to find _id from database to send a PUT request

I'm having a problem identifying a 'task' in mongoDB from my frontend angular.
This question is the most similar to my question but here it just says req.body.id and doesn't really explain how they got that.
This question involves what I am trying to do: update one document in a collection upon a click. What it does in the frontend isn't important. I just want to change the status text of the Task from "Active" to "Completed" onclick.
First I create a task and stick it in my database collection with this code:
createTask(): void {
const status = "Active";
const taskTree: Task = {
_id: this._id,
author: this.username,
createdBy: this.department,
intendedFor: this.taskFormGroup.value.taskDepartment,
taskName: this.taskFormGroup.value.taskName,
taskDescription: this.taskFormGroup.value.taskDescription,
expectedDuration: this.taskFormGroup.value.expectedDuration,
status: status
};
this.http.post("/api/tasks", taskTree).subscribe(res => {
this.taskData = res;
});
}
When I make this post to the backend, _id is magically filled in!
I'm just not sure how I can pass the id to the put request in nodejs router.put('/:id') when I'm pushing it from the frontend like this:
completeTask(): void {
const status = "Completed";
const taskTree: Task = {
_id: this._id,
author: this.username,
createdBy: this.department,
intendedFor: this.taskFormGroup.value.taskDepartment,
taskName: this.taskFormGroup.value.taskName,
taskDescription: this.taskFormGroup.value.taskDescription,
expectedDuration: this.taskFormGroup.value.expectedDuration,
status: status
};
console.log(taskTree);
this.http.put("/api/tasks/" + taskTree._id, taskTree).subscribe(res => {
this.taskData = res;
console.log(res);
});
}
In the template I have a form that's filled in and the data is immediately outputted to a task 'card' on the same page.
When I send the put request from angular, I get a response in the backend just fine of the response I ask for in task-routes.js:
router.put("/:id", (req, res, next) => {
const taskData = req.body;
console.log(taskData);
const task = new Task({
taskId: taskData._id,
author: taskData.author,
createdBy: taskData.createdBy,
intendedFor: taskData.intendedFor,
taskName: taskData.taskName,
taskDescription: taskData.taskDescription,
expectedDuration: taskData.expectedDuration,
status: taskData.status
})
Task.updateOne(req.params.id, {
$set: task.status
},
{
new: true
},
function(err, updatedTask) {
if (err) throw err;
console.log(updatedTask);
}
)
});
The general response I get for the updated info is:
{
author: 'there's a name here',
createdBy: 'management',
intendedFor: null,
taskName: null,
taskDescription: null,
expectedDuration: null,
status: 'Completed'
}
Now I know _id is created automatically in the database so here when I click create task & it outputs to the 'card', in the console log of task after I save() it on the post request, taskId: undefined comes up. This is all fine and dandy but I have to send a unique identifier from the frontend Task interface so when I send the 'put' request, nodejs gets the same id as was 'post'ed.
I'm quite confused at this point.
So I finally figured this out...In case it helps someone here's what finally worked:
First I moved my update function and (patch instead of put) request to my trigger service:
Trigger Service
tasks: Task[] = [];
updateTask(taskId, data): Observable<Task> {
return this.http.patch<Task>(this.host + "tasks/" + taskId, data);
}
I also created a get request in the trigger service file to find all the documents in a collection:
getTasks() {
return this.http.get<Task[]>(this.host + "tasks");
}
Angular component
Get tasks in ngOnInit to list them when the component loads:
ngOnInit() {
this.triggerService.getTasks().subscribe(
tasks => {
this.tasks = tasks as Task[];
console.log(this.tasks);
},
error => console.error(error)
);
}
Update:
completeTask(taskId, data): any {
this.triggerService.updateTask(taskId, data).subscribe(res => {
console.log(res);
});
}
Angular template (html)
<button mat-button
class="btn btn-lemon"
(click)="completeTask(task._id)"
>Complete Task</button>
// task._id comes from `*ngFor="task of tasks"`, "tasks" being the name of the array
//(or interface array) in your component file. "task" is any name you give it,
//but I think the singular form of your array is the normal practice.
Backend Routes
GET all tasks:
router.get("", (req, res, next) => {
Task.find({})
.then(tasks => {
if (tasks) {
res.status(200).json(tasks);
} else {
res.status(400).json({ message: "all tasks not found" });
}
})
.catch(error => {
response.status(500).json({
message: "Fetching tasks failed",
error: error
});
});
});
Update 1 field in specified document (status from "Active" to "Completed"):
router.patch("/:id", (req, res, next) => {
const status = "Completed";
console.log(req.params.id + " IT'S THE ID ");
Task.updateOne(
{ _id: req.params.id },
{ $set: { status: status } },
{ upsert: true }
)
.then(result => {
if (result.n > 0) {
res.status(200).json({
message: "Update successful!"
});
}
})
.catch(error => {
res.status(500).json({
message: "Failed updating the status.",
error: error
});
});
});
Hope it helps someone!

How to update existing MongoDB document with Nested JSON using Angular?

I am trying to store JSON array to the existing document with the id who logged in. I don't have an idea how to post this array to backend.
cake.component.ts
export class CakeComponent implements OnInit {
form: FormGroup;
constructor(
public fb: FormBuilder,
private api: ApiService
) { }
ngOnInit() {
this.submitForm();
}
submitForm() {
this.form = this.fb.group({
url: ['', [Validators.required]],
width : ['', [Validators.required]],
height: ['', [Validators.required]]
})
}
submitForm() {
if (this.form.valid) {
this.api.AddCake(this.form.value).subscribe();
}
}
}
Existing MongoDB document Cakes
{
"id": "0001",
"type": "donut",
"name": "Cake"
}
Expected Output
{
"id": "0001",
"type": "donut",
"name": "Cake",
"image": {
"url": "images/0001.jpg",
"width": 200,
"height": 200
}
}
Here is the basic code, please update it accordingly :
/** You can split this code into multiple files, schema into a file &
mongoDB connectivity into a common file & actual DB update can be placed where ever you want */
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
const cakeSchema = new Schema({
id: String,
type: String,
name: String,
image: {
url: String,
width: Number,
height: Number
}
});
const cakeModel = mongoose.model('Cakes', cakeSchema, 'Cakes');
let form = {
"url": "images/0001.jpg",
"width": 200,
"height": 200
}
async function myDbConnection() {
const url = 'yourDBConnectionString';
try {
await mongoose.connect(url, { useNewUrlParser: true });
console.log('Connected Successfully')
let db = mongoose.connection;
// You can use .update() or .updateOne() or .findOneAndUpdate()
let resp = await cakeModel.findOneAndUpdate({ id: '0001' }, { image: form }, { new: true });
console.log('successfully updated ::', resp)
db.close();
} catch (error) {
console.log('Error in DB Op ::', error);
db.close();
}
}
module.exports = myDbConnection();
Update :
In case if you're using mongoDB driver but not mongoose :
const MongoClient = require('mongodb').MongoClient;
// Connection URL
const url = 'yourDBConnectionString';
// Database Name
const dbName = 'test';
// Create a new MongoClient
const client = new MongoClient(url);
let form = {
"url": "images/0001.jpg",
"width": 200,
"height": 200
}
// Use connect method to connect to the Server
client.connect(async function (err) {
if (err) console.log('DB connection error ::', err)
console.log("Connected successfully to server");
try {
// You can use .update() or .updateOne() or .findOneAndUpdate()
let resp = await client.db(dbName).collection('Cakes').findOneAndUpdate({ id: '0001' }, { $set: { image: form } }, { returnOriginal: false });
console.log('successfully updated ::', resp , 'resp value ::', resp.value)
client.close();
} catch (error) {
console.log('Error in DB Op ::', error);
client.close();
}
});

Resources