GraphQL查询报Cannot read properties of null (reading '_doc')错误
运行GraphQL查询遇到的错误
执行查询时返回的报错信息如下:
{ "errors": [ { "message": "Cannot read properties of null (reading '_doc')", "locations": [ { "line": 38, "column": 5 } ], "path": [ "songs", 0, "creator" ] } ], "data": null }
使用的查询语句如下:
query { songs { song_file_name song_type song_size user_name creator { email } } }
定义的Schema代码如下:
const { buildSchema } = require('graphql'); module.exports = buildSchema(` type Song { _id: ID! song_file_name: String! song_type: String! song_size: Int! user_name: String! creator: User! } type User { _id: ID! email: String! password: String createdSongs: [Song!] } input SongInput { song_file_name: String! song_type: String! song_size: Int! user_name: String! } input UserInput { email: String! password: String! } type RootQuery { songs: [Song!]! } type RootMutation { createSong(songInput: SongInput): Song createUser(userInput: UserInput): User } schema { query: RootQuery mutation: RootMutation } `);
从报错路径可定位到songs数组第一条数据的creator字段解析异常,需要明确错误产生原因、修复方案,同时获取GraphQL关联数据设计与实现相关的进阶学习资源。
错误产生原因
报错是两个问题叠加导致的:
- 关联数据查询逻辑缺失:使用原生
buildSchema构建Schema时,GraphQL不会自动处理跨集合/表的关联查询,默认resolver只会读取父返回对象上的同名字段。当前songs查询的resolver只查询了歌曲本身的数据,没有关联查询creator对应的用户信息,解析creator字段时拿到的是null值,后续尝试读取null对象上Mongoose文档内部的_doc属性时直接抛出异常。 - Schema约束与实际数据不匹配:Schema中给
Song类型的creator字段加了!非空标记,意味着GraphQL预期该字段永远不会返回null,但实际数据库里要么第一条歌曲关联的创建者id对应用户已被删除、要么创建歌曲时没有正确写入creator关联id,本身就存在creator为null的脏数据,非空校验直接阻断了整个查询返回。
修复方案
按以下步骤调整即可解决问题:
- 先清理历史脏数据:检查数据库songs集合中第一条记录的creator关联字段,修复空值、无效用户id的问题,保证所有歌曲记录都绑定了存在的用户id。
- 补全关联字段解析逻辑:如果使用Mongoose作为ODM,在songs查询的链式调用中添加
.populate('creator'),在查询歌曲时一并把关联的用户数据查出来;如果不使用populate,就单独为Song类型的creator字段编写resolve方法,拿到当前歌曲对象存储的creator用户id后,去users集合查询对应用户数据返回。 - 对齐Schema约束和业务逻辑:如果业务上确实允许歌曲不绑定创建者,就把Schema中
creator: User!的非空标记去掉,改成creator: User,避免非空校验直接阻断整个查询。
进阶学习建议
关联数据是GraphQL项目落地的核心模块,针对目前的学习阶段,可以按以下路径推进:
- 先吃透GraphQL的字段解析规则:GraphQL执行查询时是逐字段递归解析的,父字段resolve返回的对象会作为子字段resolver的第一个入参,嵌套关联字段不会自动拉取数据,必须手动编写resolve逻辑或者借助工具优化查询。
- 重点掌握DataLoader的用法:手写关联查询最容易出现经典的N+1查询问题,DataLoader是GraphQL生态通用的批量查询、缓存工具,几乎所有生产环境的GraphQL服务都会用它优化关联查询性能,官方仓库有非常详细的用法示例。
- 可以尝试切换到更工程化的GraphQL服务实现,比如Apollo Server,相比原生
buildSchema的写法,它的resolver结构更清晰,嵌套字段的resolve逻辑写法更直观,官方文档包含完整的关联数据设计、性能优化最佳实践,跟着官方示例练习一遍就能打通关联实现的底层逻辑。 - 练习时不要只照搬教程代码,每写一个resolver就加日志打印入参和返回值,明确每一层字段解析时拿到的数据结构,搞懂每一步数据的流转逻辑,比硬记教程步骤效率高很多。
内容的提问来源于stack exchange,提问作者TheNomadicAspie
相关产品推荐
相关产品推荐

