Knex带.where()的查询在GraphQL中返回null求助
Knex + Apollo Server带where条件查询返回null问题排查
问题概述
用Knex和Apollo Server搭建API时,不带where条件的getUsers查询能正常返回所有用户,但带where条件的getUser查询(无论用id、firstName还是email等字段)始终返回null,服务运行正常,SQL日志显示查询语句格式正确。
相关代码片段
服务端入口代码
import { ApolloServer } from 'apollo-server' import knex from './knex' import { resolvers, typeDefs } from './schema' import { UserSQLDataSource } from './schema/users/datasource' const server = new ApolloServer({ typeDefs, resolvers, dataSources: () => { return { userDb: new UserSQLDataSource(knex), } }, uploads: false, cors: { origin: ['https://studio.apollographql.com'], credentials: true, }, }) server.listen(4003).then(({ url }) => { console.log(`Server listening on url ${url}`) })
用户数据源实现(含问题代码)
import { SQLDatasource } from '../../schema/datasources' export class UserSQLDataSource extends SQLDatasource { constructor(knex) { super(knex, 'users') } async getUsers() { return await this.db(this.tableName) } async getUser(id) { try { const query = this.db(this.tableName).where({ id: id }) console.log(query.toSQL()) return await query } catch (error) { console.error(error) throw error } } }
GraphQL用户类型定义
import { gql } from 'apollo-server' export const userTypeDefs = gql` extend type Query { user(id: ID!): User! users: [User!]! } type User { id: ID! firstName: String! lastName: String! userName: String! email: String! password_hash: String! token: String! createdAt: String! updatedAt: String! } `
用户Resolver代码
const users = async (_, { input }, { dataSources }) => { const users = await dataSources.userDb.getUsers(input) return users } const user = async (_, { id }, { dataSources }) => { const user = await dataSources.userDb.getUser(id) return user } export const userResolvers = { Query: { user, users }, }
查询日志输出
Server listening on url http://localhost:4003/ { method: 'select', options: {}, timeout: false, cancelOnTimeout: false, bindings: [ '1' ], __knexQueryUid: 'sH05Z4l3pgdNm5mY9YPkeu6', sql: 'select * from `users` where `id` = ?' }
问题原因分析
- 返回值类型不匹配:Knex的
where()查询默认返回数组(即使只匹配一条数据),但GraphQL的user查询定义返回的是单个User!对象。当Resolver返回数组时,Apollo无法将数组映射到单个User类型,最终返回null。 - 非空类型约束:GraphQL定义
user: User!为非空类型,若查询结果为空数组,直接返回会触发类型不匹配错误,表现为返回null。
解决方案
1. 修改数据源查询逻辑,返回单个对象
在getUser方法中,使用Knex的first()方法直接获取单个结果(替代返回数组):
async getUser(id) { try { // 使用first()直接获取匹配的第一条数据,返回单个对象而非数组 const user = await this.db(this.tableName).where({ id }).first(); // 若未找到用户,抛出明确错误(符合GraphQL非空类型约束) if (!user) { throw new Error(`User with id ${id} not found`); } return user; } catch (error) { console.error(error); throw error; } }
2. 验证数据存在性
确认数据库中存在对应id的用户记录,可直接执行日志中的SQL语句(如select * from users where id = 1)验证是否有返回结果。
3. 可选:处理ID类型转换(若数据库ID为数字)
GraphQL的ID类型默认传递为字符串,若数据库中id为数字类型,可显式转换确保匹配:
// 将字符串ID转为数字 const user = await this.db(this.tableName).where({ id: parseInt(id, 10) }).first();
验证修改
修改后重新启动服务,执行user(id: "1")查询,应正常返回单个用户对象;若未找到用户,会抛出明确的错误信息而非返回null。
内容的提问来源于stack exchange,提问作者Teseu
相关产品推荐
相关产品推荐

