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

如何在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现有数据的存储结构不匹配:

  1. 关联方向搞反了:你定义的是pages属于sites(每个page对应一个site),但实际数据是sites包含多个pages的ID数组,属于一对多的反向关联——一个site对应多个page,而page并不存储site的ID。
  2. 现有数据未更新:即使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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 16:50:23