我正在尝试将包含图像上传和 CSV 上传的表单保存到我的 MongoDB。我正在使用 Node 模块 Multer 和 CSVtoJSON 来完成此任务。我已经能够自己完成每项任务,但正在努力让它们以相同的形式保存到数据库中。经过无数次尝试后,代码目前没有抛出任何错误,我只是在浏览器中得到“Cannot POST /”。这些文件已正确保存到我的上传文件夹中。我相信失败是我在创建数据库条目之前将文件转换为 JSON 的逻辑。
这是我的 app.js 文件:
const express = require('express') ;
const app = express();
const dotenv = require('dotenv');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const fs = require('fs');
const path = require('path');
const multer = require('multer');
const csv = require('csvtojson');
const imageSchema = require('./models/Profile');
dotenv.config({ path: './config/config.env' });
mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true, useUnifiedTopology: true
}, err => {
console.log('Database is connected')
}
);
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.set("view engine", "ejs");
const storage = multer.diskStorage({
destination: (req, file, cb) => {
if (file.fieldname === "image") { // if uploading resume
cb(null, 'uploads/images');
} else if (file.fieldname === "csv") { // else uploading image
cb(null, 'uploads/csvs');
} else {
console.log("A CSV file is required to create a user profile.");
}
// if (file.mimetype=='image/jpeg' || file.mimetype=='image/png' || file.mimetype=='jpg') {
// cb(null, './uploads/images/');
// } else if (file.mimetype=='text/csv' || file.mimetype=='csv') {
// cb(null, './uploads/csvs/');
// } else (file.mimetype != 'image/jpeg' || file.mimetype != 'image/png' || file.mimetype != 'jpg' || file.mimetype != 'text/csv' || file.mimetype != 'csv') {
// // cb(null, false)
// console.log("File type is not supported. Please upload correct file types.");
// }
},
filename: (req, file, cb) => {
cb(null, Date.now() + '_' + file.originalname)
}
});
const upload = multer({ storage }).fields([
{name: 'image', maxCount: 1},
{name: 'csv', maxCount: 1}
]);
// Retriving the image
app.get('/', (req, res) => {
imageSchema.find({}, (err, items) => {
if (err) {
console.log(err);
}
else {
res.render('app', { items });
}
});
});
// Uploading the image
app.post('/', upload), (req, res, next) => {
// const conversion = csv().fromFile(req.file.path).then((jsonObj) => {
// console.log(jsonObj);
// // csvSchema.insertMany(jsonObj,(err,data)=>{
// // if(err){
// // console.log(err);
// // }
// // });
// })
// Convert CSV to json
function csvToJson(filePath){
csv()
.fromFile(filePath)
.then((jsonObj)=>{
console.log(jsonObj);
})
}
const obj = {
name: req.body.name,
img: {
data: fs.readFileSync(path.join(__dirname + '/uploads/images' + req.file.filename)),
contentType: 'image/png image/jpeg'
},
csv: {
data: csvToJson(fs.readFileSync(path.join(__dirname + '/uploads/csvs' + req.file.filename))),
contentType: 'text/csv'
}
}
imageSchema.create(obj, (err, item) => {
if (err) {
console.log(err);
}
else {
item.save();
res.redirect('/');
}
});
fs.unlinkSync(filePath);
};
const PORT = process.env.PORT || 5000;
app.listen(PORT, () =>
console.log(`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`)
);
这是我的架构的简化版本:
var mongoose = require('mongoose');
var csvSchema = new mongoose.Schema({
A: { type: Number },
B: { type: Number },
C: { type: Number },
D: { type: Number },
E: { type: Number }
});
var imageSchema = new mongoose.Schema({
name: String,
img:
{
data: Buffer,
contentType: String
},
csv: [csvSchema],
createdAt: {type: Date, default: Date.now}
});
module.exports = mongoose.model('Image', imageSchema);
这是我的 app.ejs 文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.0/css/bulma.min.css">
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css"
integrity="sha256-+N4/V/SbAFiW1MPBCXnfnP9QSN3+Keu+NlB+0ev/YKQ="
crossorigin="anonymous"
/>
<title>Create Profile</title>
</head>
<script>
// 1. Display filename when select file
// 2. Clear filename when form reset
document.addEventListener('DOMContentLoaded', () => {
// 1. Display file name when select file
let fileInputs = document.querySelectorAll('.file.has-name')
for (let fileInput of fileInputs) {
let input = fileInput.querySelector('.file-input')
let name = fileInput.querySelector('.file-name')
input.addEventListener('change', () => {
let files = input.files
if (files.length === 0) {
name.innerText = 'No file selected'
} else {
name.innerText = files[0].name
}
})
}
// 2. Remove file name when form reset
let forms = document.getElementsByTagName('form')
for (let form of forms) {
form.addEventListener('reset', () => {
console.log('a')
let names = form.querySelectorAll('.file-name')
for (let name of names) {
name.innerText = 'No file selected'
}
})
}
})
</script>
<body>
<section class="hero is-dark">
<div class="hero-body">
<div class="container">
<div class="columns is-vcentered">
<span style="font-size: 80px;">
<i class="fas fa-user-alt size:7x"></i>
</span>
<div class="column">
<h1 class="title">
Create User Profile
</h1>
<h2 class="subtitle">
All fields are required
</h2>
</div>
</div>
</div>
</div>
</section>
<section class="section">
<div class="container">
<div class="columns">
<div class="column is-two-fifths">
<box class="box">
<h1 class="title">Create Profile</h1>
<hr>
<form class="form" action="/" method="POST" enctype="multipart/form-data">
<div class="field">
<label class="label" for="name">Name</label>
<input class="input" type="text" id="name" placeholder="Enter your name"
value="" name="name" required>
</div>
<div class="field">
<label class="label" for="image">Profile Picture</label>
<div class="file has-name is-link is-fullwidth">
<input class="file-input" type="file" id="image"
name="image" value="" required>
<label class="file-label" for="image">
<span class="file-cta">
<span class="file-icon">
<i class="fas fa-upload"></i>
</span>
<span class="file-label">
Choose an image...
</span>
</span>
<span class="file-name"'>
No file selected
</span>
</label>
</input>
</div>
</div>
<div class="field">
<label class="label" for="csv">Data</label>
<div class="file has-name is-link is-fullwidth">
<input class="file-input" type="file" id="csv"
name="csv" value="" required>
<label class="file-label" for="csv">
<span class="file-cta">
<span class="file-icon">
<i class="fas fa-upload"></i>
</span>
<span class="file-label">
Choose a CSV file...
</span>
</span>
<span class="file-name">
No file selected
</span>
</label>
</input>
</div>
</div><hr>
<div class="control has-text-centered">
<button class="button is-success" type="submit"><b>Submit</b></button>
</div>
</form>
</box>
</div>
<hr>
<div class="column">
<h1 class="title">Manage Profiles</h1>
<hr>
<div>
<% items.forEach(function(image) { %>
<box class="box">
<div>
<div>
<h5 class="title"><%= image.name %></h5>
</div><hr>
<div class='card-content is-flex is-horizontal-center'>
<img src="data:image/<%=image.img.contentType%>;base64,
<%=image.img.data.toString('base64')%>">
</div>
<div>
<h6 class="subtitle"><%= image.csv %></h6>
</div>
</div>
</box>
<% }) %>
</div>
</div>
</div>
</div>
</section>
</body>
<style>
section.section {
padding: 30px 0px;
}
#hero-image {
width: 99px;
}
.is-horizontal-center {
justify-content: center;
}
button.button {
width: 33%;
}
</style>
</html>
这是我的 package.json 文件:
{
"name": "combiningimgcsvuploads",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"csvtojson": "^2.0.10",
"dotenv": "^8.2.0",
"ejs": "^3.1.3",
"express": "^4.17.1",
"mongoose": "^5.9.21",
"multer": "^1.4.2"
},
"devDependencies": {
"nodemon": "^2.0.4"
}
}
任何可以提供的帮助将不胜感激。我对任何和所有建议持开放态度——即使这意味着完全不同的方法,只要它更有效。