You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native健身数据提交MongoDB的格式适配问题求助

健身数据收集应用的Schema与数据格式适配问题

问题背景

我正在开发一款React Native应用,用于收集用户输入的可变健身数据并提交至MongoDB数据库。收集的信息包含动作名称以及由重量和次数组成的数组,现在纠结是修改Mongoose Schema适配现有前端数据格式,还是修改前端代码将数据处理为匹配Schema的格式。

当前Mongoose Schema

const exerciseSchema = new mongoose.Schema([{
  exerciseName: String,
  sets: [{
    weight: Number,
    reps: Number
  }]
}]);

前端收集的数据格式

[
  {"Seated Leg Extensions":
    [{"weight":"12","reps":"22"},
     {"weight":"12","reps":"2"}]},
  {"Shrugs":
    [{"weight":"12","reps":"33"}]
  }
]

前端核心代码

import React, { useState } from 'react';
import axios from 'axios';
import { View, ScrollView, Modal, Picker, Text, TouchableOpacity, TextInput, StyleSheet, Button, FlatList  } from 'react-native';
import myExerciseList from './ExerciseList';
import {ExerciseView} from './Sets';

const exercises = myExerciseList

const ExerciseList = () => {

  const [dataFromChild, setDataFromChild] = useState([]);

  const handleChildData = (data) => {
    setDataFromChild([...dataFromChild, data]);
    console.log(dataFromChild)
  };

  const [views, setViews] = useState([]);
  const [visible, setVisible] = useState(false);
  const [selectedValue, setSelectedValue] = useState(null);

  //Form data to be sent to the database
  const [formData, setFormData] = useState(
    [{
      exerciseName: '',
      sets: [{
        weight: '',
        reps: ''
      }]
    }]
  )

  const handlePress = (item) => {
    setSelectedValue(item)
    const newView = <View  key={views.length} >
                      <Text>Exercise: {item.name}</Text>
                      <ExerciseView exerciseName={item.name} onData={handleChildData} ></ExerciseView>
                    </View>;
    setViews([...views, newView]);
    setVisible(false);
  };

  const submitAll = async (event) => {
    event.preventDefault()
    const dataSend = JSON.stringify(dataFromChild)
    console.log(dataSend)

    const updatedFormData = dataFromChild.map((exercise) => {
      const exerciseName = Object.keys(exercise)[0]
      const sets = exercise[exerciseName].map((set) => {
        return {
          weight: set.weight,
          reps: set.reps
        }
      })
      return {
        exerciseName,
        sets
      }
    })
    setFormData({
      exercises: updatedFormData
    })
    
    console.log(formData)
      
    try {
      const response = await axios.post('http://localhost:3000/api/v1/myworkouts', formData);
      console.log(response.data);
    } catch (error) {
      console.error(error);
    }
    console.log(dataSend)
  }

  return ()

export default ExerciseList;

后端Express路由代码

const express = require('express');
const router = express.Router();
const Exercise = require('../models/workouts');

// Create a new exercise
router.post('/', async (req, res) => {
  const exercise = new Exercise({
    exerciseName: req.body.exerciseName,
    sets: req.body.sets,  
    weight: req.body.weight,
    reps: req.body.reps,
  });
  try {
    const newExercise = await exercise.save();
    res.status(201).json(newExercise);
  } catch (err) {
    res.status(400).json({ message: err.message });
  }
});

module.exports = router;

解决方案建议

优先修改前端数据处理逻辑,适配现有Schema

现有Mongoose Schema的设计更合理,明确的结构便于后续查询、统计(比如按动作名称筛选、计算总重量等)。前端当前的键值对格式会增加数据库操作的复杂度,不建议为它修改Schema。

具体修改点:

  1. 修正数据类型转换:前端收集的重量和次数是字符串,需转为数字匹配Schema的Number类型:
    const sets = exercise[exerciseName].map((set) => {
      return {
        weight: Number(set.weight),
        reps: Number(set.reps)
      }
    })
    
  2. 避免异步状态更新的坑:setFormData是异步操作,直接用formData发请求会拿到旧值,应直接使用转换后的updatedFormData:
    // 移除setFormData相关代码,直接使用updatedFormData
    try {
      // 若后端支持单条创建,循环提交多个动作
      const responses = await Promise.all(updatedFormData.map(exercise => 
        axios.post('http://localhost:3000/api/v1/myworkouts', exercise)
      ));
      console.log('所有数据提交成功', responses);
    } catch (error) {
      console.error(error);
    }
    
  3. 修复后端路由冗余字段:后端代码里错误添加了weight和reps,这些已包含在sets数组中,需移除:
    router.post('/', async (req, res) => {
      const exercise = new Exercise({
        exerciseName: req.body.exerciseName,
        sets: req.body.sets
      });
      try {
        const newExercise = await exercise.save();
        res.status(201).json(newExercise);
      } catch (err) {
        res.status(400).json({ message: err.message });
      }
    });
    
    若想批量提交多个动作,可新增后端批量路由:
    router.post('/batch', async (req, res) => {
      try {
        const exercises = await Exercise.insertMany(req.body.exercises);
        res.status(201).json(exercises);
      } catch (err) {
        res.status(400).json({ message: err.message });
      }
    });
    
    前端对应发送{ exercises: updatedFormData }即可。

不推荐修改Schema适配前端格式

如果修改Schema适配前端的动态键格式,会导致:

  • 数据库查询困难,无法直接按exerciseName筛选、排序
  • 数据结构不规范,后续扩展(如添加动作类型、备注)会非常麻烦

内容的提问来源于stack exchange,提问作者Diego Guardiola

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 12:05:03