英文:
How do I search and edit a specific item on Mongodb?
问题
I am building a banking application with MERN stack and have a form on the Create Account Page that saves name, email, password, and balance to a table of users on Monogodb. I want to be able to then go to another form on the Withdraw/Deposit Page and enter an amount and email and it search through the table and update that user's balance.
I tried to connect directly to mongoose and then use findOneAndUpdate and $set to find the email and change the balance but, it is not changing the balance.
Deposit Page
import { useEffect, useState } from "react";
import { useNavigate, useLocation } from 'react-router-dom';
import React from "react";
import Card from "../../partials/Card";
const mongoose = require('mongoose');
mongoose.connect('http://localhost:4000/users');
function DepositPage() {
const navigate = useNavigate();
const location = useLocation();
const [show, setShow] = useState(true);
const [status, setStatus] = useState('');
return (
<Card
bgcolor="dark"
header="Deposit"
status={status}
body={show ?
<DepositForm setShow={setShow} setStatus={setStatus}/> :
<DepositMsg setShow={setShow}/>}
/>
)
}
function DepositMsg(props){
return (
<>
<h5>User Successfully Deposited into Their Account</h5>
<button type="submit"
className="btn btn-light"
onClick={() => props.setShow(true)}>
Make Another Deposit
</button>
</>
);
}
function DepositForm(props){
const [email, setEmail] = useState('');
const [amount, setAmount] = useState('');
function handle(){
users.findOneAndUpdate({email: email}, {$set:{balance: amount}}, {new: true}, (err, doc) => {
if (err) {
console.log("error updating data");
}
console.log(doc)
})
props.setStatus('');
props.setShow(false);
}
return(
<>
Email<br/>
<input type="input"
className="form-control"
placeholder="Enter email"
value={email}
onChange={e => setEmail(e.currentTarget.value)}/><br/>
Amount<br/>
<input type="number"
className="form-control"
placeholder="Enter amount"
value={amount}
onChange={e => setAmount(e.currentTarget.value)}/><br/>
<button type="submit"
className="btn btn-light"
onClick={handle}>
Deposit
</button>
</>
);
}
export default DepositPage
Router Page
const express = require('express')
const router = express.Router()
const schemas = require('../models/schemas')
router.post('/users/:a', async(req, res) => {
const {name, email, password, balance} = req.body
const action = req.params.a
switch(action) {
case "send":
const userData = {name: name, email: email, password: password, balance: balance}
const newUser = new schemas.Users(userData)
const saveUser = await newUser.save()
if (saveUser) {
res.send('User created')
} else {
res.send('Failed to create user. Please make sure all fields are filled and try again.')
}
break;
default:
res.send('Invalid Request')
break
}
res.end()
})
module.exports = router
index.js (server)
const express = require('express')
const cors = require('cors')
const bodyParser = require('body-parser')
const router = require('./routes/router')
const mongoose = require('mongoose')
require('dotenv/config')
const app = express()
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended:false}))
const corsOptions = {
origin: '*',
credentials: true,
optionSuccessStatus: 200
}
app.use(cors(corsOptions))
app.use('/', router)
const dbOptions = {useNewUrlParser:true, useUnifiedTopology:true}
mongoose.connect(process.env.DB_URI, dbOptions)
.then(() => console.log('DB Connected!'))
.catch(err => console.log(err))
const port = process.env.PORT || 4000
const server = app.listen(port, () => {
console.log(`Server is running on port ${port}`)
})
schemas page
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const userSchema = new Schema({
name: {type:String, required:true},
email: {type:String, required:true},
password: {type:String, required:true},
balance: {type:Number, required:true},
entryDate: {type:Date, default:Date.now}
})
const Users = mongoose.model('Users', userSchema, 'users')
const mySchemas = {'Users':Users}
module.exports = mySchemas
CreateAccount Page
import { useState, useEffect } from "react";
import axios from "axios";
import { useNavigate, useLocation } from 'react-router-dom';
import React from 'react';
import Card from '../../partials/Card';
function CreateAccountPage() {
const navigate = useNavigate();
const location = useLocation();
const [show, setShow] = useState(true);
const [status, setStatus] = useState('');
let { from } = location.state || { from: { pathname: "/" } };
return (
<Card
bgcolor="dark"
header="Create Account"
status={status}
body={show ?
<CreateForm setShow={setShow}/> :
<CreateMsg setShow={setShow}/>}
/>
)
}
function CreateMsg(props){
return(<>
<h5>Success</h5>
<button type="submit"
className="btn btn-light"
onClick={() => props.setShow(true)}>Add another account</button>
</>);
}
function CreateForm(props){
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [balance, setBalance] = useState(0);
const [error, setError] = useState('')
const axiosPostData = async() => {
const postData = {
name: name,
email: email,
password: password,
balance: balance
}
await axios.post('http://localhost:4000/users/send', postData)
.then(res => setError(<p className="success">{res.data}</p>))
}
const handleSubmit = (e) => {
e.preventDefault()
axiosPostData()
props.setShow(false);
}
return (
<>
<form name="createAcctForm" onSubmit={handleSubmit} >
Name<br/>
<input type="text"
id="name"
className="form-control"
placeholder="Enter name"
value={name}
onChange={e => setName(e.currentTarget.value)}
required
/><br/>
Email address<br/>
<input type="text"
id
<details>
<summary>英文:</summary>
I am building a banking application with MERN stack and have a form on the Create Account Page that saves name, email, password, and balance to a table of users on Monogodb. I want to be able to then go to another form on the Withdraw/Deposit Page and enter an amount and email and it search through the table and update that users balance.
I tried to connect directly to mongoose and then use findOneandUpdate and $set to find the email and change the balance but, it is not changing the balance.
Deposit Page
import { useEffect, useState } from "react"
import { useNavigate, useLocation } from 'react-router-dom'
import React from "react";
import Card from "../../partials/Card";
const mongoose = require('mongoose');
mongoose.connect('http://localhost:4000/users');
function DepositPage() {
const navigate = useNavigate();
const location = useLocation();
const [show, setShow] = useState(true);
const [status, setStatus] = useState('');
return (
<Card
bgcolor="dark"
header="Deposit"
status={status}
body={show ?
<DepositForm setShow={setShow} setStatus={setStatus}/> :
<DepositMsg setShow={setShow}/>}
/>
)
}
function DepositMsg(props){
return (<>
<h5>User Successfully Deposited into Their Account</h5>
<button type="submit"
className="btn btn-light"
onClick={() => props.setShow(true)}>
Make Another Deposit
</button>
</>);
}
function DepositForm(props){
const [email, setEmail] = useState('');
const [amount, setAmount] = useState('');
function handle(){
users.findOneAndUpdate({email: email}, {$set:{balance: amount}}, {new: true}, (err, doc) => {
if (err) {
console.log("error updating data");
}
console.log(doc)
})
props.setStatus('');
props.setShow(false);
}
return(<>
Email<br/>
<input type="input"
className="form-control"
placeholder="Enter email"
value={email}
onChange={e => setEmail(e.currentTarget.value)}/><br/>
Amount<br/>
<input type="number"
className="form-control"
placeholder="Enter amount"
value={amount}
onChange={e => setAmount(e.currentTarget.value)}/><br/>
<button type="submit"
className="btn btn-light"
onClick={handle}>
Deposit
</button>
</>);
}
export default DepositPage
Router Page
const express = require('express')
const router = express.Router()
const schemas = require('../models/schemas')
router.post('/users/:a', async(req, res) => {
const {name, email, password, balance} = req.body
const action = req.params.a
switch(action) {
case "send":
const userData = {name: name, email: email, password: password, balance: balance}
const newUser = new schemas.Users(userData)
const saveUser = await newUser.save()
if (saveUser) {
res.send('User created')
} else {
res.send('Failed to create user. Please make sure all fields are filled and try again.')
}
break;
default:
res.send('Invalid Request')
break
}
res.end()
})
module.exports = router
index.js (server)
const express = require('express')
const cors = require('cors')
const bodyParser = require('body-parser')
const router = require('./routes/router')
const mongoose = require('mongoose')
require('dotenv/config')
const app = express()
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended:false}))
const corsOptions = {
origin: '*',
credentials: true,
optionSuccessStatus: 200
}
app.use(cors(corsOptions))
app.use('/', router)
const dbOptions = {useNewUrlParser:true, useUnifiedTopology:true}
mongoose.connect(process.env.DB_URI, dbOptions)
.then(() => console.log('DB Connected!'))
.catch(err => console.log(err))
const port = process.env.PORT || 4000
const server = app.listen(port, () => {
console.log(Server is running on port ${port}
)
})
schemas page
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const userSchema = new Schema({
name: {type:String, required:true},
email: {type:String, required:true},
password: {type:String, required:true},
balance: {type:Number, required:true},
entryDate: {type:Date, default:Date.now}
})
const Users = mongoose.model('Users', userSchema, 'users')
const mySchemas = {'Users':Users}
module.exports = mySchemas
CreateAccount Page
import { useState, useEffect } from "react"
import axios from "axios"
import { useNavigate, useLocation } from 'react-router-dom'
import React from 'react';
import Card from '../../partials/Card';
function CreateAccountPage() {
const navigate = useNavigate();
const location = useLocation();
const [show, setShow] = useState(true);
const [status, setStatus] = useState('');
let { from } = location.state || { from: { pathname: "/" } };
return (
<Card
bgcolor="dark"
header="Create Account"
status={status}
body={show ?
<CreateForm setShow={setShow}/> :
<CreateMsg setShow={setShow}/>}
/>
)
}
function CreateMsg(props){
return(<>
<h5>Success</h5>
<button type="submit"
className="btn btn-light"
onClick={() => props.setShow(true)}>Add another account</button>
</>);
}
function CreateForm(props){
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [balance, setBalance] = useState(0);
const [error, setError] = useState('')
const axiosPostData = async() => {
const postData = {
name: name,
email: email,
password: password,
balance: balance
}
await axios.post('http://localhost:4000/users/send', postData)
.then(res => setError(<p className="success">{res.data}</p>))
}
const handleSubmit = (e) => {
e.preventDefault()
axiosPostData()
props.setShow(false);
}
return ( <>
<form name="createAcctForm" onSubmit={handleSubmit} >
Name<br/>
<input type="text"
id="name"
className="form-control"
placeholder="Enter name"
value={name}
onChange={e => setName(e.currentTarget.value)}
required
/><br/>
Email address<br/>
<input type="text"
id="email"
className="form-control"
placeholder="Enter email"
value={email}
onChange={e => setEmail(e.currentTarget.value)}
required
/><br/>
Password<br/>
<input type="password"
id="password"
className="form-control"
placeholder="Enter password"
value={password}
onChange={e => setPassword(e.currentTarget.value)}
minLength="8"
/><br/>
<button type="submit"
className="btn btn-light"
>Create Account</button>
</form>
</>
)
}
export default CreateAccountPage
Also I am very sorry if my formatting is rough. I am still very new to using stackoverflow.
</details>
# 答案1
**得分**: 1
编辑:
MongoDB和Mongoose是与服务器端环境中的数据库进行交互的后端技术。在前端(React)方面,您不能直接连接到MongoDB数据库或使用Mongoose。相反,您需要从React组件向后端API发出HTTP请求,后端API将使用Mongoose处理数据库操作。Node.js的`require`关键字可以用于服务器或终端运行时。但在支持ecma script 6+的环境中,`import`也可以使用。对于后端:
```javascript
// 根据您的JavaScript运行时选择import或require
// const mongoose = require('mongoose');
// import mongoose from 'mongoose';
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/database-name', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'Mongo error:'));
db.once('open', () => {
console.log('Connected!');
});
上面的代码段应该从您的库或NPM模块中导入mongoose到后端服务器API(express)。使用mongoose需要后端JavaScript环境进行编译和运行。由于Node.js和其他后端在系统级别上利用C++、C、Rust等,所以需要配置mongoose包以与Mongo API交互。在mongoose.connect
方法中,我们使用Mongo DB的默认端口号27017建立网络连接。database-name
可以是任何名称。如果您使用的是Mongo社区版、付费版或其他版本,在启动数据库引擎后,这应该完成与数据库交互的连接和配置。我喜欢使用MongoDB Compass程序作为我的MongoDB的GUI界面 https://www.mongodb.com/products/compass,但您也可以在终端环境中运行mongo脚本。
接下来,您需要根据需要定义一个Mongo模式或多个模式。在Node.js中,参见require
语法:
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: String,
email: String,
password: String,
balance: Number,
});
const User = mongoose.model('User', userSchema);
module.exports = User;
将此保存到名为'models'或类似'models'的文件夹中。然后,为每个模式创建一个描述的新文件,例如'User.js'。这取决于您想要称其为update、depositAmount或类似名称。
import User from '../models/User';
// 定义update、deposit等函数逻辑
async function handle() {
try {
const updatedUser = await User.findOneAndUpdate(
{ email: email },
{ $inc: { balance: parseInt(amount) } },
{ new: true }
);
console.log(updatedUser);
props.setStatus('');
props.setShow(false);
} catch (error) {
console.log("Error updating data", error);
}
}
使用mongoose的内置方法findOneAndUpdate
,我们可以更新用户数据。Mongo附带一个独特的uid,可以帮助识别用户。
您还问及需要在表单内设置前端API请求的事项。使用fetch
API或axios
,将定义更新用户数据的函数放在名为'helpers'的文件夹中。我们将向服务器发出HTTP请求,实际处理与React代码的数据库交互。在一个新组件中,比如说'DepositPage.js',我们可以向我们的服务器发出HTTP请求并在User集合上启动更新。
根据您提供的组件代码,React组件应该类似于:
import React, { useState } from "react";
import axios from "axios";
function DepositPage() {
const [email, setEmail] = useState("");
const [amount, setAmount] = useState("");
const [status, setStatus] = useState("");
const [show, setShow] = useState(true);
const handleDeposit = async (e) => {
e.preventDefault();
try {
const response = await axios.post("/api/deposit", {
email: email,
amount: amount,
});
console.log(response.data);
setStatus("User successfully deposited into their account");
} catch (error) {
console.error("Error depositing:", error);
setStatus("Error depositing. Please try again.");
}
setShow(false);
};
const handleAnotherDeposit = () => {
setShow(true);
setStatus("");
setEmail("");
setAmount("");
};
return (
<div>
<h2>Deposit</h2>
{show ? (
<form onSubmit={handleDeposit}>
<label>
Email:
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</label>
<br />
<label>
Amount:
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
</label>
<br />
<button type="submit">Deposit</button>
</form>
) : (
<div>
<h4>{status}</h4>
<button onClick={handleAnotherDeposit}>Make Another Deposit</button>
</div>
)}
</div>
);
}
export default DepositPage;
我假设您正在使用express
,但HTTP是相同的。axios.post()
是React.js向服务器/API发送数据的方式。使用参数/api/deposit
,应该为这些端点设置了express路由。
如果您需要更多关于设置express的信息,请告诉我。在import
和require
之间的选择大多取决于您的选择风格或特定环境要求。
编辑:
// React组件
import React, { useState } from "react";
import axios from "axios";
function CreateUser() {
const FULL_API_URL = '服务器的本地主机路径和端口';
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [balance, setBalance] = useState("");
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post(`${FULL_API_URL}/users/send`, {
name,
email,
password,
balance
});
console.log(response.data);
} catch (error) {
console.error("Error creating user:", error);
// 错误逻辑 ...
}
};
return (
<div>
<h2>Create User</h2>
<
<details>
<summary>英文:</summary>
EDIT:
MongoDB and Mongoose are backend techs for interacting with DBs from a server-side environment. On the frontend (React) side, you cannot directly connect to the MongoDB database or use Mongoose. Instead, you need to make HTTP requests from your React components to your backend API, which will handle the database operations using Mongoose. The Node.js `require` keyword can be used on your server or terminal runtime. But `import` will work as well in ecma script 6+ supporting environments too. For the back-end side:
// choose between import or require depending on your javascript runtime
// const mongoose = require('mongoose');
// import mongoose from 'mongoose';
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/database-name', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'Mongo error:'));
db.once('open', () => {
console.log('Connected!');
});
That above snippet should import mongoose from your library or NPM modules into the backend server API (express). Using mongoose requires a backend javascript environment to compile and run. Since Node.js and other backends utilize C++, C, Rust, etc. at the system level, mongoose package will need to be configured to interact with the Mongo API. In the `mongoose.connect` method we establish a network with the default port number of Mongo DB, 27017. The `database-name` can be any. If you are using mongo community version, paid, or other versions, after you start your database engine, this should complete the connection and configuration for your react app to interact with the database. I like to use the MongoDB Compass program for a GUI interface with my mongo DBs https://www.mongodb.com/products/compass
But you could also run mongo scripts in a terminal env
Your next steps would be to define a Mongo schema or schemas depending on how many data structures you need. In Node.js, see the `require` syntax:
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: String,
email: String,
password: String,
balance: Number,
});
const User = mongoose.model('User', userSchema);
module.exports = User;
Save that into a folder named 'models' or another like 'structures'. Then for each schema make a new file describing it, like 'User.js'
It depends if you want to call it update, depositAmount, or something like that.
import User from '../models/User';
// define update, deposit, etc. function logic
async function handle() {
try {
const updatedUser = await User.findOneAndUpdate(
{ email: email },
{ $inc: { balance: parseInt(amount) } },
{ new: true }
);
console.log(updatedUser);
props.setStatus('');
props.setShow(false);
} catch (error) {
console.log("Error updating data", error);
}
}
Use the built-in method from mongoose `findOneAndUpdate` and we can update the user data. Mongo comes with a unique uid that can assist in identifying users.
You also asked about needing to set up your front end API requests inside of the form. Using `fetch` API or `axios`, put functions that define updating user data in a folder called 'helpers'. We will make HTTP requests to the server to actually handle the database interactions with the react code. In a new component, let's say 'DepositPage.js' we can make an HTTP request to our server and initiate an update on the User collection.
Based on your code from the component you, the react component should look something like:
import React, { useState } from "react";
import axios from "axios";
function DepositPage() {
const [email, setEmail] = useState("");
const [amount, setAmount] = useState("");
const [status, setStatus] = useState("");
const [show, setShow] = useState(true);
const handleDeposit = async (e) => {
e.preventDefault();
try {
const response = await axios.post("/api/deposit", {
email: email,
amount: amount,
});
console.log(response.data);
setStatus("User successfully deposited into their account");
} catch (error) {
console.error("Error depositing:", error);
setStatus("Error depositing. Please try again.");
}
setShow(false);
};
const handleAnotherDeposit = () => {
setShow(true);
setStatus("");
setEmail("");
setAmount("");
};
return (
<div>
<h2>Deposit</h2>
{show ? (
<form onSubmit={handleDeposit}>
<label>
Email:
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</label>
<br />
<label>
Amount:
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
</label>
<br />
<button type="submit">Deposit</button>
</form>
) : (
<div>
<h4>{status}</h4>
<button onClick={handleAnotherDeposit}>Make Another Deposit</button>
</div>
)}
</div>
);
}
export default DepositPage;
I'm assuming you are using `express`, but the HTTP is the same.
`axios.post()` is how react.js can send data to your server/API. With the param `/api/deposit`, the express routes should be set up for these endpoints.
If you need more info on setting up express let me know. Choosing between import and require is mostly determined by your style of choice, or your specific environment requirements.
EDIT:
// React component
import React, { useState } from "react";
import axios from "axios";
function CreateUser() {
const FULL_API_URL = 'local host path and port to server'
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [balance, setBalance] = useState("");
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post(`${FULL_API_URL}/users/send`, {
name,
email,
password,
balance
});
console.log(response.data);
} catch (error) {
console.error("Error creating user:", error);
// error logic stuff ...
}
};
return (
<div>
<h2>Create User</h2>
<form onSubmit={handleSubmit}>
<label>
Name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<br />
<label>
Email:
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</label>
<br />
<label>
Password:
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</label>
<br />
<label>
Balance:
<input
type="number"
value={balance}
onChange={(e) => setBalance(e.target.value)}
/>
</label>
<br />
<button type="submit">Create User</button>
</form>
</div>
);
}
export default CreateUser;
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论