使用Mongoose访问Schema.Types.ObjectId关联值:按训练名查运动标题
嘿,我来帮你搞定这个查询需求!根据你描述的训练管理应用场景,核心是利用Mongoose的populate()方法来关联查询Workout和它关联的Exercise数据,下面一步步给你理清楚实现方式:
1. 先确认模型的正确定义
首先得保证你的两个模型引用关系配置正确,这是关联查询的基础:
Exercise模型(exercise.js)
需要包含你要查询的title字段,示例如下:
const mongoose = require('mongoose'); const exerciseSchema = new mongoose.Schema({ title: { type: String, required: true // 运动标题必填,比如“俯卧撑” }, // 你可以按需添加其他字段,比如组数、次数、时长等 }); module.exports = mongoose.model('Exercise', exerciseSchema);
Workout模型(workout.js)
exercises字段要定义为Exercise模型的ObjectId数组,通过ref指定关联的模型名称:
const mongoose = require('mongoose'); const workoutSchema = new mongoose.Schema({ name: { type: String, required: true // 训练名称,比如“上肢训练” }, creatorEmail: { type: String, required: true // 创建者邮箱 }, exercises: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Exercise' // 这里必须和Exercise模型导出的名称一致 }] }); module.exports = mongoose.model('Workout', workoutSchema);
2. 控制器实现按训练名称查询并关联运动标题
在Workout控制器里,我们用findOne()(或find()如果允许多个同名训练)配合populate(),只取出我们需要的Exercise标题:
const Workout = require('../models/workout'); // 按训练名称查询关联的运动标题 exports.getWorkoutWithExercises = async (req, res) => { try { // 从请求参数中获取训练名称,比如请求地址是 /workouts?name=上肢训练 const targetWorkoutName = req.query.name; // 查询指定名称的训练,并关联查询exercises的title字段 // `-_id`表示不返回Exercise的_id,按需选择是否保留 const workout = await Workout.findOne({ name: targetWorkoutName }) .populate('exercises', 'title -_id'); if (!workout) { return res.status(404).json({ message: '未找到对应的训练记录' }); } // 整理返回结果,只返回需要的信息 const responseData = { workoutName: workout.name, creator: workout.creatorEmail, exercises: workout.exercises // 这里已经是只包含title的数组了 }; res.status(200).json(responseData); } catch (error) { res.status(500).json({ message: '查询失败', error: error.message }); } };
如果需要支持模糊查询(比如输入“上肢”就能匹配“上肢训练”),可以把查询条件改成正则:
const workout = await Workout.findOne({ name: { $regex: targetWorkoutName, $options: 'i' } // 'i'表示忽略大小写 }) .populate('exercises', 'title -_id');
3. 配置路由(routes.js)
把这个查询接口挂载到路由上:
const express = require('express'); const router = express.Router(); const workoutController = require('../controllers/workout'); // GET请求:通过训练名称查询关联运动 router.get('/workouts', workoutController.getWorkoutWithExercises); module.exports = router;
额外注意点
- 确保你在创建Workout的时候,已经正确将Exercise的ObjectId存入了
exercises数组,否则populate()会返回空数组。 - 如果需要返回Exercise的更多字段,比如
title和sets(组数),可以把populate的第二个参数改成'title sets'。
内容的提问来源于stack exchange,提问作者Darran Blackweir
相关产品推荐
相关产品推荐

