NestJS中Mongoose的populate失效及关联查询无结果问题排查
NestJS + Mongoose 关联查询异常问题
问题现象
在NestJS项目中使用Mongoose时遇到两个问题:
populate关联查询无法正常工作- 通过Night文档中teams数组的ObjectId查询Team集合时返回空数组
服务方法代码
async getTeamsByNightId(id: string) { const night = await this.nightModel.findById({_id: id}); console.log('night: ', night); //@TODO Why is populate not working? //const night = (await this.nightModel.findById({_id: id})).populate('teams'); if (night) { const teamIds = night.teams.map((teamId) => teamId.toString()); console.log('teamIds: ', teamIds); try { const teams = await this.teamModel.find({ _id: { $in: night.teams } }).exec(); console.log('teams: ', teams); } catch (error) { console.log(error); } } else { throw new NotFoundException('No matching Night found'); } }
控制台输出
Mongoose: nights.findOne({ _id: ObjectId("6552ad936a93bab2b686496d") }, {}) night: { _id: new ObjectId("6552ad936a93bab2b686496d"), name: 'a', askedQuestions: [], teams: [ new ObjectId("6552ada76a93bab2b6864972") ], password: '487254', __v: 1 } teamIds: [ '6552ada76a93bab2b6864972' ] Mongoose: teams.find({ _id: { '$in': [ ObjectId("6552ada76a93bab2b6864972") ] } }, {}) teams: []
Schema定义
Night Schema
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; import { HydratedDocument, Types } from "mongoose"; export type NightDocument = HydratedDocument<Night>; @Schema() export class Night { @Prop() name: string; @Prop() password: string; @Prop([{ type: Types.ObjectId, ref: 'Question' }]) askedQuestions: Types.ObjectId[]; @Prop([{ type: Types.ObjectId, ref: 'Team' }]) teams: Types.ObjectId[];; } export const NightSchema = SchemaFactory.createForClass(Night);
Team Schema
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { HydratedDocument, Types } from 'mongoose'; export type TeamDocument = HydratedDocument<Team>; @Schema() export class Team { @Prop() username: string; @Prop() password: string; } export const TeamSchema = SchemaFactory.createForClass(Team);
添加Team到Night的方法
async addTeamToNight(teamId: string, addTeamToNightDTO: AddTeamToNightDTO) { const name = addTeamToNightDTO.name; const password = addTeamToNightDTO.password; const night = await this.nightModel.findOne({name, password}).exec(); if (night) { night.teams.push(new Types.ObjectId(teamId)); return await night.save(); } else { throw new NotFoundException('Name or Password incorrect'); } }
疑问
请问我哪里操作出错了?
问题原因及解决方案
1. 查询Team返回空数组的原因
你存入Night的teamId对应的文档很可能不存在于Team集合中。可以直接在MongoDB客户端执行db.teams.find({_id: ObjectId("6552ada76a93bab2b6864972")}),验证该ObjectId是否真的对应一个Team文档。另外,检查传入addTeamToNight的teamId是否正确,有没有拼写或格式错误。
2. populate失效的原因
你写的(await this.nightModel.findById({_id: id})).populate('teams')写法错误,Mongoose的populate需要在查询链中调用,或者对已查询的文档执行execPopulate()。正确写法有两种:
- 链式调用(推荐):
const night = await this.nightModel.findById(id).populate('teams').exec(); - 对已获取的文档执行:
const night = await this.nightModel.findById(id); await night.populate('teams');
3. 额外修复点
- Night Schema中
teams字段多了一个分号,修正为:teams: Types.ObjectId[]; - 在
addTeamToNight方法中,建议先验证teamId对应的Team是否存在,再添加到Night的teams数组,避免存入无效ObjectId:async addTeamToNight(teamId: string, addTeamToNightDTO: AddTeamToNightDTO) { const name = addTeamToNightDTO.name; const password = addTeamToNightDTO.password; // 先验证Team存在 const teamExists = await this.teamModel.exists({_id: teamId}); if (!teamExists) { throw new NotFoundException('Team not found'); } const night = await this.nightModel.findOne({name, password}).exec(); if (night) { night.teams.push(new Types.ObjectId(teamId)); return await night.save(); } else { throw new NotFoundException('Name or Password incorrect'); } }
内容的提问来源于stack exchange,提问作者user3481441
相关产品推荐
相关产品推荐

