GraphQL查询中MongoDB关联对象UTS、Media返回null的问题排查
问题描述
数据库模型
- 每个
Mediablock关联一个UTS对象和一个Media对象。 - 每个
UTS对象包含rawText和normalisedText字段 - 每个
Media对象包含url和timestamp字段
schema.prisma 代码
datasource db { provider = "mongodb" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model Mediablock { id String @id @default(auto()) @map("_id") @db.ObjectId // 生成唯一ID UTS UTS @relation(fields: [utsId], references: [id]) utsId String @unique @map("uts_id") @db.ObjectId Media Media @relation(fields: [mediaId], references: [id]) mediaId String @unique @map("media_id") @db.ObjectId } model UTS { id String @id @default(auto()) @map("_id") @db.ObjectId rawText String normalisedText String createdAt DateTime @default(now()) Mediablock Mediablock? } // Mediablocks包含Video对象并关联回Mediablock // mediablockId必须使用@db.ObjectId匹配Mediablock的ID类型 model Media { id String @id @default(auto()) @map("_id") @db.ObjectId url String createdAt DateTime @default(now()) Mediablock Mediablock? }
resolvers 代码
const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); module.exports = { Query: { allMediablocks: () => prisma.mediablock.findMany(), allMedia: () => prisma.media.findMany(), allUTS: () => prisma.uts.findMany(), }, };
typedefs 代码
module.exports = ` type Mediablock { id: ID! uts: UTS media: Media # 文本先生成时可为null } type UTS { id: ID! rawText: String! normalisedText: String! } type Media { id: ID! url: String! createdAt: String! } # Query类型用于定义所有客户端可执行的查询及返回类型 # 此处allMediablocks查询返回0个或多个Mediablock对象 type Query { allMediablocks: [Mediablock] allMedia: [Media] allUTS: [UTS] } `;
种子文件代码
const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); const mediaData = [ { UTS: { create: { rawText: 'Welcome', normalisedText: 'welcome', }, }, Media: { create: { url: 'https://www.youtube.com/watch?v=kq9aShH2Kg4', createdAt: '2022-09-29T12:00:00.000Z', } } } ]; async function main() { console.log(`开始初始化数据...`); for (const d of mediaData) { const mediablock = await prisma.Mediablock.create({ data: d, }); console.log(`创建Mediablock,ID:${mediablock.id}`); } console.log(`\n数据初始化完成。`); } main() .then(async () => { await prisma.$disconnect(); }) .catch(async (e) => { console.error(e); await prisma.$disconnect(); process.exit(1); });
问题详情
执行allMediablocks查询时,无法获取UTS或Media的数据,返回结果如下:
查询语句:
query allMediaBlocks { allMediablocks { uts { normalisedText } media { url } } }
返回结果:
{ "data": { "allMediablocks": [ { "uts": null, "media": null } ] } }
数据库中已存在对应关联对象的引用,但返回的uts和media均为null,请问哪里出错了?是resolvers写法错误、MongoDB的schema结构不正确还是其他问题?
解决方案
核心问题是Prisma查询默认不会自动加载关联数据,必须显式指定include选项包含关联模型,同时要保证返回字段名与typedefs定义一致。
1. 修改resolvers中的allMediablocks查询
更新查询逻辑,显式包含关联的UTS和Media,并转换字段名匹配typedefs的小写定义:
allMediablocks: async () => { const mediablocks = await prisma.mediablock.findMany({ include: { UTS: true, Media: true } }); // 将Prisma返回的首字母大写字段转为小写,匹配typedefs return mediablocks.map(block => ({ ...block, uts: block.UTS, media: block.Media, UTS: undefined, Media: undefined })); },
2. 验证关联数据正确性
确认数据库中Mediablock文档的uts_id和media_id字段,是否正确关联到对应的UTS和Media文档ID,种子文件的关联创建写法是正确的,一般无需调整。
补充说明
你的MongoDB schema结构没有问题,关联定义符合Prisma要求,问题仅出在查询时未主动加载关联数据。如果后续有大量关联查询需求,可以使用GraphQL的DataLoader优化批量查询性能,当前场景下显式include即可解决问题。
内容的提问来源于stack exchange,提问作者nopassport1
相关产品推荐
相关产品推荐

