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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 20:35:26