【问题标题】:Images not appearing in the MongoDB database图像未出现在 MongoDB 数据库中
【发布时间】:2021-03-25 22:37:42
【问题描述】:

我正在将一个包含图像的表单上传到我的 mongodb 数据库,所有数据都在那里,但是图像没有出现在数据库中。这是否与我无法添加 propertyImage: req.file.path 的事实有关,因为我收到“typeError cannot read property of 'path'od undefined”的错误。我希望它们在数据库中的原因是让我能够获取它们并将图像附加到相关产品。

我有下面的后端代码,至于前端,我假设我需要使用 formData 创建一些东西,以便发送带有图像的文本字段。如果是这样,有人可以指出我正确的方向,因为我不确定从哪里开始,这样它就不会影响我的用户授权设置,如下所述。

const express = require('express');
const userRouter = express.Router();
const passport = require('passport');
const passportConfig = require('../passport');
const JWT = require('jsonwebtoken');
const User = require('../models/User');
const Property = require('../models/Property');
const multer = require('multer')

const storage = multer.diskStorage({
    destination: (req, file, callback) => {
        callback(null, "./uploads/");
        
    },
    filename: (req, file, callback) => {
        callback(null, file.originalname);
    }
})
const upload = multer({storage: storage});

const signToken = userID => {
    return JWT.sign({
        iss : "Moove",
        sub : userID
    },"Moove",{expiresIn :"1h"});
}

userRouter.post('/register',(req,res)=>{
    const {username,name,email,password} = req.body;
    User.findOne({email},(err,user)=>{
        if(err)
            res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
        if(user)
            res.status(400).json({message : {msgBody: "Email has already been used, Please log in", msgError : true}});
        else{
            const newUser = new User({username,name,email,password});
            newUser.save(err=>{
                if(err)
                    res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
                    else
                    res.status(201).json({message : {msgBody: "Account Successfully Created", msgError : false}});
            });
        };
    });
});

 userRouter.post('/login',passport.authenticate('local',{session : false}),(req,res)=>{
    if(req.isAuthenticated()){
       const {_id,username,password} = req.user;
       const token = signToken(_id);
       res.cookie('access_token',token,{httpOnly: true, sameSite:true}); 
       res.status(200).json({isAuthenticated : true,user : {username,password}});
    }
});

 userRouter.get('/logout',passport.authenticate('jwt',{session : false}),(req,res)=>{
    res.clearCookie('access_token');
    res.json({user:{username:''},success : true})
});

 userRouter.post('/property', upload.single('propertyImage'),passport.authenticate('jwt',{session : false}),(req,res)=>{
    console.log(req.file);
    const property = new Property({
        street: req.body.street,
        town: req.body.town,
        area: req.body.area,
        PostCode: req.body.PostCode,
        NoBeds: req.body.NoBeds,
        NoBath: req.body.NoBath,
        NoLivingRooms: req.body.NoLivingRooms,
        askingPrice: req.body.askingPrice,
        propertyImage: req.file
    });

    property.save(err=> {
        if(err)
         res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
        else{
            req.user.properties.push(property);
            
            req.user.save(err=> {
                if(err)
                 res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
                 else
                 res.status(200).json({message: {msgBody: "Successfully created property", msgError : false}});
            })
        }
    })
});
userRouter.get('/properties',passport.authenticate('jwt',{session : false}),(req,res)=>{
    User.findById({_id : req.user._id}).populate('properties').exec((err,document)=>{
        if(err)
            res.status(500).json({message : {msgBody : "Error has occured", msgError: true}});
        else{
            res.status(200).json({properties : document.properties, authenticated : true});
        }
    });
});
userRouter.get('/property',passport.authenticate('jwt',{session : false}),(req,res)=>{
    User.findById({_id : req.user._id}).populate('properties').exec((err,document)=>{
        if(err)
            res.status(500).json({message : {msgBody : "Error has occured", msgError: true}});
        else{
            res.status(200).json({properties : document.properties, authenticated : true});
        }
    });
});
userRouter.get('/authenticated',passport.authenticate('jwt',{session : false}),(req,res)=>{
    const {username} = req.user;
    res.status(200).json({isAuthenticated : true, user: {username}})
});


module.exports = userRouter;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
import React, {useState,useContext, useEffect} from 'react'
import PropertyItem from './PropertyItem';
import PropertyService from '../Services/PropertyService';
import Message from './Message'
import {AuthContext} from '../Context/AuthContext';


const Properties = props =>{
    const [property,setProperty] = useState({
        // propertyImage: "",
        street : "",
        town : "",
        area : "",
        PostCode : "",
        NoBeds : "",
        NoBath : "",
        NoLivingRooms : "",
        askingPrice: "",
    })
    const [properties,setProperties] = useState ([]);
    // const [propertyImage,setPropertyImage] = useState ([]);
    const [message,setMessage] = useState(null);
    const authContext = useContext(AuthContext);

    useEffect(()=>{
        PropertyService.getProperties().then(data =>{
            setProperties(data.properties);
        });
    },[]);

    const onSubmit = e =>{
        e.preventDefault();
        PropertyService.postProperty(property).then(data =>{
            const {message } = data;
            resetForm();
            if(!message.msgError){
                PropertyService.getProperties().then(getData =>{
                    setProperties(getData.properties);
                    setMessage(message);
                });
            }
            else if(message.msgBody === "UnAuthorized"){
                setMessage(message);
                authContext.setUser({username : ""});
                authContext.setIsAuthenticated(false);
            }
            else{
                setMessage(message);
            }
        },[]);
    }
     
    const onChange = e =>{
        setProperty({...property,[e.target.name] : e.target.value})
    }
    // const onChangefile = e =>{
    //     setPropertyImage(e.target.files[0])
    // }

    const resetForm = ()=>{
        setProperty({
        propertyImage: "",
        street : "",
        town : "",
        area : "",
        PostCode : "",
        NoBeds : "",
        NoBath : "",
        NoLivingRooms : "",
        askingPrice : "",
        });
    }

    return(
        <div>
            <ul className="">
                {
                    properties.map((property) =>{
                        return <PropertyItem key={property._id} 
            property={property} 
            street={property.street}
            town={property.town}
            area={property.area}
            PostCode={property.PostCode}
            NoBeds={property.NoBeds}
            NoBath={property.NoBath}
            NoLivingRooms={property.NoLivingRooms}
            askingPrice={property.askingPrice}
            propertyImage={property.propertyImage}
            />
                    },[])
                }
            </ul>
            <br/>
            <form onSubmit={onSubmit} encType="multipart/form-data">
                <label htmlFor="street">Street Name</label>
                <input type="text" 
                       name="street" 
                       value={property.street}
                       onChange={onChange}
                       className=""
                       placeholder="street name"/>
                <label htmlFor="town">Town</label>
                <input type="text" 
                       name="town" 
                       value={property.town}
                       onChange={onChange}
                       className=""
                       placeholder="town"/>
                <label htmlFor="area">Area</label>
                <input type="text" 
                       name="area" 
                        value={property.area}
                       onChange={onChange}
                       className=""
                       placeholder="area"/>
                <label htmlFor="postcode">Postcode</label>
                <input type="text" 
                       name="PostCode" 
                       value={property.PostCode}
                       onChange={onChange}
                       className=""
                       placeholder="Postcode"/>
                <label htmlFor="NoBeds">Beds</label>
                <input type="number" 
                       name="NoBeds" 
                       value={property.NoBeds}
                       onChange={onChange}
                       className=""
                       placeholder="Number of beds"/>
                <label htmlFor="NoBath">Bathrooms</label>
                <input type="number" 
                       name="NoBath" 
                        value={property.NoBath}
                       onChange={onChange}
                       className=""
                       placeholder="Number of bathrooms"/>
                <label htmlFor="NoLivingRooms">Living Rroom</label>
                <input type="number" 
                       name="NoLivingRooms" 
                        value={property.NoLivingRooms}
                       onChange={onChange}
                       className=""
                       placeholder="Number of living rooms"/>
                <label htmlFor="askingPrice">Asking Price(£)</label>
                <input type="number" 
                       name="askingPrice" 
                        value={property.askingPrice}
                       onChange={onChange}
                       className=""
                       placeholder="£249,999"/>
                <label htmlFor="propertyImage">Property Images</label>
                <input type="file" 
                       filename="propertyImage" 
                       
                       onChange={onChange}
                       className=""
                       placeholder="Upload property images"/>
                <button className="" 
                        type="submit">Submit</button>
            </form>
            {message ? <Message message={message}/> : null}
        </div>
    );

}


export default Properties

【问题讨论】:

    标签: node.js reactjs mongodb express multer


    【解决方案1】:

    您必须以不同于普通文本字段的方式处理文件输入 &lt;input type="file"...。文件输入对正常字段的反应不同。他们接受一个 on change 事件,当用户选择一个文件时更新,并转换为blob。您需要将其转换为 base64,然后将 base64 发送到服务器(或适当的图像托管服务,例如 cloudinary)。

    这是一个演示:

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      <input type="file" id='file'/>
      <script src='./app.js'></script>
      
    </body>
    </html>
    
    

    app.js

    const fileReader = document.getElementById('file')
    
    const getBase64 = (file) => {
      return new Promise((resolve, reject) => {
        const fr = new FileReader()
    
        console.log(file instanceof Blob) // Should be true
        
        fr.readAsDataURL(file)
        fr.onerror = reject
        fr.onload = function () {
          resolve(fr.result)
        }
      })
    }
    
    fileReader.addEventListener('change', (e) => {
      console.log(e.target.files[0])
      getBase64(e.target.files[0]).then((res) => console.log(res) )
    })
    
    

    在上面的 JS 中,我们将文件阅读器输入作为一个元素获取并为其设置一个 onChange 事件,该事件调用 getBase64 函数。 getBase64 函数返回一个 Promise,它在文件被读取后实现。在该函数中,我们创建一个新的 FileReader 作为fr,然后调用fr.readDataAsURL(file) 将您的文件转换为base64,然后在fr.onload 中解析它。然后,您可以使用 getBase64(file).then(res =&gt; doSomething(res)) 调用它的输出。

    用这两个文件创建一个目录,然后测试功能。当您选择一个文件时,您应该会看到一个非常长的字符串 (Base64),这就是您应该发布到您的图像托管服务的内容。

    我相信你可以将 base64 发布到 MongoDB,虽然不推荐。

    【讨论】:

    • 如果不推荐,最好的方法是什么?
    • 如果您打算上传大量文件,图像可能会占用大量空间,因此使用云提供商可能会更好/提供更好的性能。 Cloudinary 免费提供大量存储空间,而且设置起来相对简单。你基本上通过你的快递服务器传递base64并调用一个cloudinary上传方法,它返回图像的url。另一种选择是 Amazon S3,我没有亲自使用过。这里有一些关于你为什么要这样做的更多信息:mongodb.com/blog/post/…
    猜你喜欢
    • 2018-05-07
    • 1970-01-01
    • 2020-10-17
    • 1970-01-01
    • 1970-01-01
    • 2021-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多