如何在GraphQL中通过MongoDB ObjectId数组关联查询pages数据?
问题描述
我在MongoDB的sites集合中有若干文档,每个文档包含pages属性,是ObjectId类型的数组,结构如下:
// sites集合中的文档示例 { _id: ObjectId("5e607b2643e2640056466402"), title: "Some Title", ... pages: [ ObjectId("5e57bcbd0166a10055c43bb7"), ObjectId("5e5ba2630166a10055c5c952"), ... ] }
我用GraphQL+Apollo+Prisma获取数据,希望返回pages对应的实际数据(title和uri),而不是仅ID。
初始配置如下:
schema.prisma
model pages { id String @id @default(auto()) @map("_id") @db.ObjectId title String? uri String? } model sites { id String @id @default(auto()) @map("_id") @db.ObjectId pages String[] @db.ObjectId title String? url String? }
typeDefs.js
type pages { id: ID! title: String uri: String } type sites { id: ID! pages: [String] title: String url: String }
Resolver初始代码
allSites: () => prisma.sites.findMany(),
发送查询:
query myQuery { allSitesRecursive { title pages } }
响应只返回pages的ID数组:
{ "data": { "allSites": [ { "title": "Some Title", "pages": [ "5dc9630226b1b2005952c4b5", "5e5797020166a10055c41f94", ... ] } ] } }
我尝试修改Resolver用include:
allSites: () => prisma.sites.findMany({ include: { pages: true } }),
但报错:
Invalid scalar field `pages` for include statement on model sites. This model has no relations, so you can't use include with it. Note, that include statements only accept relation fields.,
于是我修改了schema.prisma,添加关联:
model pages { id String @id @default(auto()) @map("_id") @db.ObjectId title String? uri String? sites sites? @relation(fields: [sitesId], references: [id]) sitesId String? @db.ObjectId } model sites { id String @id @default(auto()) @map("_id") @db.ObjectId pages pages[] title String? url String? }
同时修改typeDefs中sites的pages类型为[pages],但查询后pages数组为空:
query AllSites { allSites { pages { title uri } title } }
响应:
{ "data": { "allSites": [ { "pages": [], "title": "www.some-website.com" }, ... ] } }
请问哪里操作错了?
问题原因与解决步骤
问题出在你修改schema时,Prisma的关联逻辑和MongoDB现有数据的存储结构不匹配:
- 关联方向搞反了:你定义的是
pages属于sites(每个page对应一个site),但实际数据是sites包含多个pages的ID数组,属于一对多的反向关联——一个site对应多个page,而page并不存储site的ID。 - 现有数据未更新:即使schema改对了,现有MongoDB的
pages文档里没有sitesId字段,Prisma找不到关联关系,所以返回空数组。
正确的实现方案(无需修改现有MongoDB数据结构)
步骤1:修正schema.prisma的关联定义
因为你的数据是sites存pages的ID数组,需要用@relation指定关联字段,让Prisma匹配现有数据结构:
model pages { id String @id @default(auto()) @map("_id") @db.ObjectId title String? uri String? // 定义反向关联,匹配sites到pages的映射 sites sites[] @relation("SiteToPages", fields: [id], references: [pagesIds]) } model sites { id String @id @default(auto()) @map("_id") @db.ObjectId // 定义关联字段,关联到pages的id pages pages[] @relation("SiteToPages", fields: [pagesIds], references: [id]) // 映射MongoDB中原本的pages数组字段 pagesIds String[] @db.ObjectId @map("pages") title String? url String? }
核心点:
- 用
pagesIds映射MongoDB里的pages字段(因为要把原数组字段转为关联字段,需要重命名) - 通过
@relation指定关联名称"SiteToPages",明确sites.pages关联的是pages.id,对应sites.pagesIds里的ID数组
步骤2:更新typeDefs.js
确保sites类型的pages返回对象数组:
type pages { id: ID! title: String uri: String } type sites { id: ID! pages: [pages] title: String url: String }
步骤3:修改Resolver
现在可以用include关联查询pages数据:
allSites: () => prisma.sites.findMany({ include: { pages: true } }),
步骤4:发送GraphQL查询
使用之前的查询语句即可:
query AllSites { allSites { pages { title uri } title } }
为什么之前的方案不行?
你之前的schema定义是pages存储sitesId,但现有MongoDB的pages文档没有这个字段,Prisma无法找到对应的关联关系,因此查询返回空的pages数组。上面的方案无需修改现有数据,仅调整Prisma的关联映射即可匹配你当前的MongoDB数据结构。
内容的提问来源于stack exchange,提问作者nopassport1
相关产品推荐
相关产品推荐

