0

我正在尝试将包含图像上传和 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"
  }
}

任何可以提供的帮助将不胜感激。我对任何和所有建议持开放态度——即使这意味着完全不同的方法,只要它更有效。

4

1 回答 1

0

在继续下一个代码块之前,您可能需要等待 csvToJson 函数完成。这可以通过异步等待来完成。另外,我认为您缺少退货声明。尝试这个:

    // Convert CSV to json
    async function csvToJson(filePath){
        csv()
            .fromFile(filePath)
            .then((jsonObj)=>{
                console.log(jsonObj);
                return jsonObj;              
            })
    }
   
    const json_data = await csvToJson(fs.readFileSync(path.join(__dirname + '/uploads/csvs' + req.file.filename))); 
    const json_data_string = JSON.stringify(json_data);

    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: json_data_string,
            contentType: 'application/json'
        }
    }
于 2020-07-04T14:46:23.593 回答