GraphQL 查询操作 #
查询基础 #
Query 是 GraphQL 中用于获取数据的操作类型,类似于 REST API 中的 GET 请求。
text
┌─────────────────────────────────────────────────────────────┐
│ Query 操作特点 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ✅ 只读操作:不修改数据 │
│ ✅ 并行执行:多个字段可并行获取 │
│ ✅ 精确获取:只返回请求的字段 │
│ ✅ 嵌套查询:一次请求获取关联数据 │
│ │
└─────────────────────────────────────────────────────────────┘
基本查询 #
单条记录查询 #
graphql
query {
user(id: "1") {
id
name
email
}
}
响应:
json
{
"data": {
"user": {
"id": "1",
"name": "Alice",
"email": "alice@example.com"
}
}
}
列表查询 #
graphql
query {
users {
id
name
email
}
}
响应:
json
{
"data": {
"users": [
{
"id": "1",
"name": "Alice",
"email": "alice@example.com"
},
{
"id": "2",
"name": "Bob",
"email": "bob@example.com"
}
]
}
}
嵌套查询 #
GraphQL 的强大之处在于可以一次请求获取多层嵌套的关联数据:
graphql
query {
user(id: "1") {
name
email
posts {
id
title
comments {
id
content
author {
name
}
}
}
}
}
分页查询 #
分页是处理大量数据的关键技术。GraphQL 通常使用两种分页方式。
偏移分页(Offset-based) #
graphql
query {
users(limit: 10, offset: 0) {
id
name
email
}
usersCount
}
游标分页(Cursor-based) #
游标分页更适合实时数据和高性能场景:
graphql
query {
users(first: 10, after: "cursor-value") {
edges {
node {
id
name
email
}
cursor
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
totalCount
}
}
响应:
json
{
"data": {
"users": {
"edges": [
{
"node": {
"id": "1",
"name": "Alice",
"email": "alice@example.com"
},
"cursor": "YXJyYXljb25uZWN0aW9uOjA="
}
],
"pageInfo": {
"hasNextPage": true,
"hasPreviousPage": false,
"startCursor": "YXJyYXljb25uZWN0aW9uOjA=",
"endCursor": "YXJyYXljb25uZWN0aW9uOjk="
},
"totalCount": 100
}
}
}
分页类型对比 #
text
┌─────────────────────────────────────────────────────────────┐
│ 分页方式对比 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 偏移分页(Offset): │
│ ✅ 简单直观,易于理解 │
│ ✅ 支持跳页 │
│ ❌ 大偏移量性能差 │
│ ❌ 数据变化时可能遗漏/重复 │
│ │
│ 游标分页(Cursor): │
│ ✅ 性能稳定,不受数据量影响 │
│ ✅ 数据一致性更好 │
│ ❌ 不支持跳页 │
│ ❌ 实现稍复杂 │
│ │
└─────────────────────────────────────────────────────────────┘
连接规范(Relay Style) #
Relay 风格的分页是业界标准:
graphql
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
type UserEdge {
node: User!
cursor: String!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int
}
使用示例:
graphql
query GetUsers($first: Int, $after: String) {
users(first: $first, after: $after) {
edges {
node {
id
name
}
cursor
}
pageInfo {
hasNextPage
endCursor
}
totalCount
}
}
过滤查询 #
过滤用于筛选符合条件的数据。
简单过滤 #
graphql
query {
users(status: "active") {
id
name
status
}
}
多条件过滤 #
graphql
query {
users(
status: "active"
role: "admin"
country: "US"
) {
id
name
role
country
}
}
过滤对象 #
复杂过滤使用输入对象:
graphql
query {
users(filter: {
status: "active",
age: { gte: 18, lte: 65 },
name: { contains: "Alice" }
}) {
id
name
age
status
}
}
过滤操作符 #
graphql
query {
products(filter: {
price: { gte: 10, lte: 100 },
category: { in: ["electronics", "books"] },
name: { contains: "phone", mode: INSENSITIVE },
stock: { gt: 0 },
tags: { has: "featured" }
}) {
id
name
price
category
}
}
常用操作符:
| 操作符 | 说明 | 示例 |
|---|---|---|
| eq | 等于 | { status: { eq: "active" } } |
| ne | 不等于 | { status: { ne: "deleted" } } |
| gt | 大于 | { age: { gt: 18 } } |
| gte | 大于等于 | { age: { gte: 18 } } |
| lt | 小于 | { age: { lt: 65 } } |
| lte | 小于等于 | { age: { lte: 65 } } |
| in | 包含于 | { status: { in: ["active", "pending"] } } |
| nin | 不包含于 | { status: { nin: ["deleted"] } } |
| contains | 包含 | { name: { contains: "Alice" } } |
| startsWith | 开头匹配 | { name: { startsWith: "Al" } } |
| endsWith | 结尾匹配 | { email: { endsWith: "@example.com" } } |
逻辑操作符 #
graphql
query {
users(filter: {
AND: [
{ status: { eq: "active" } },
{ OR: [
{ role: { eq: "admin" } },
{ role: { eq: "moderator" } }
]}
]
}) {
id
name
role
status
}
}
排序查询 #
排序用于控制返回数据的顺序。
单字段排序 #
graphql
query {
users(orderBy: { field: "createdAt", direction: DESC }) {
id
name
createdAt
}
}
多字段排序 #
graphql
query {
users(orderBy: [
{ field: "status", direction: ASC },
{ field: "createdAt", direction: DESC }
]) {
id
name
status
createdAt
}
}
枚举排序 #
使用枚举更简洁:
graphql
query {
users(orderBy: createdAt_DESC) {
id
name
createdAt
}
}
多枚举排序 #
graphql
query {
users(orderBy: [status_ASC, createdAt_DESC]) {
id
name
status
createdAt
}
}
搜索查询 #
全文搜索 #
graphql
query {
search(query: "GraphQL tutorial", limit: 10) {
id
title
excerpt
score
type
}
}
高亮搜索结果 #
graphql
query {
search(query: "GraphQL", highlight: true) {
id
title
highlightedTitle
content
highlightedContent
}
}
聚合搜索 #
graphql
query {
search(query: "GraphQL") {
total
items {
id
title
}
aggregations {
category {
key
count
}
author {
key
count
}
}
}
}
批量查询 #
GraphQL 允许在一个请求中查询多个资源。
多个独立查询 #
graphql
query {
users {
id
name
}
posts {
id
title
}
comments {
id
content
}
}
使用别名区分 #
graphql
query {
activeUsers: users(status: "active") {
id
name
}
inactiveUsers: users(status: "inactive") {
id
name
}
pendingUsers: users(status: "pending") {
id
name
}
}
关联数据批量查询 #
graphql
query {
user(id: "1") {
name
posts {
title
}
}
user(id: "2") {
name
posts {
title
}
}
}
使用别名:
graphql
query {
alice: user(id: "1") {
name
posts {
title
}
}
bob: user(id: "2") {
name
posts {
title
}
}
}
条件查询 #
使用指令 #
graphql
query GetDashboard($showPosts: Boolean!, $showComments: Boolean!) {
user(id: "1") {
name
posts @include(if: $showPosts) {
title
}
comments @include(if: $showComments) {
content
}
}
}
使用 @skip #
graphql
query GetUser($skipDetails: Boolean!) {
user(id: "1") {
name
email
details @skip(if: $skipDetails) {
bio
location
}
}
}
聚合查询 #
聚合查询用于统计数据。
计数 #
graphql
query {
usersCount
postsCount(status: "published")
commentsCount(userId: "1")
}
分组统计 #
graphql
query {
userStats {
status
count
}
}
响应:
json
{
"data": {
"userStats": [
{ "status": "active", "count": 150 },
{ "status": "inactive", "count": 30 },
{ "status": "pending", "count": 20 }
]
}
}
数值聚合 #
graphql
query {
orderStats {
totalOrders
totalRevenue
averageOrderValue
maxOrderValue
minOrderValue
}
}
自省查询 #
GraphQL 提供自省系统,可以查询 API 的类型信息。
查询所有类型 #
graphql
query {
__schema {
types {
name
kind
description
}
}
}
查询特定类型 #
graphql
query {
__type(name: "User") {
name
kind
fields {
name
type {
name
kind
}
args {
name
type {
name
}
}
}
}
}
查询查询操作 #
graphql
query {
__schema {
queryType {
fields {
name
description
args {
name
type {
name
}
}
}
}
}
}
查询枚举值 #
graphql
query {
__type(name: "UserStatus") {
enumValues {
name
description
}
}
}
查询最佳实践 #
1. 使用命名操作 #
graphql
query GetUserProfile($id: ID!) {
user(id: $id) {
name
email
}
}
2. 使用片段复用 #
graphql
query {
user(id: "1") {
...userFields
}
users {
...userFields
}
}
fragment userFields on User {
id
name
email
avatar
}
3. 合理使用变量 #
graphql
query SearchPosts($input: SearchInput!) {
search(input: $input) {
id
title
}
}
4. 控制查询深度 #
避免过深的嵌套查询:
graphql
query {
user(id: "1") {
posts {
comments {
author {
posts {
comments {
author {
name
}
}
}
}
}
}
}
}
5. 使用分页 #
graphql
query {
users(first: 20) {
edges {
node {
id
name
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
实战示例 #
示例一:用户列表页 #
graphql
query UserList(
$filter: UserFilter
$orderBy: UserOrderBy
$first: Int
$after: String
) {
users(
filter: $filter
orderBy: $orderBy
first: $first
after: $after
) {
edges {
node {
id
name
email
avatar
role
status
createdAt
}
cursor
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
totalCount
}
}
变量:
json
{
"filter": {
"status": { "eq": "active" }
},
"orderBy": { "field": "createdAt", "direction": "DESC" },
"first": 20
}
示例二:文章详情页 #
graphql
query PostDetail($id: ID!) {
post(id: $id) {
id
title
content
excerpt
coverImage
status
publishedAt
author {
id
name
avatar
bio
}
tags
categories {
id
name
slug
}
comments(first: 10) {
edges {
node {
id
content
createdAt
author {
id
name
avatar
}
}
}
totalCount
}
relatedPosts(limit: 5) {
id
title
excerpt
coverImage
}
}
}
示例三:仪表板统计 #
graphql
query Dashboard {
me {
id
name
avatar
}
statistics {
users {
total
active
newThisMonth
}
posts {
total
published
draft
}
comments {
total
pending
approved
}
}
recentActivity(limit: 10) {
id
type
description
createdAt
user {
name
avatar
}
}
notifications(limit: 5, unread: true) {
id
type
message
createdAt
}
}
示例四:搜索页面 #
graphql
query Search(
$query: String!
$type: [SearchType!]
$filters: SearchFilters
$first: Int
$after: String
) {
search(
query: $query
type: $type
filters: $filters
first: $first
after: $after
) {
total
items {
... on User {
id
name
avatar
email
}
... on Post {
id
title
excerpt
coverImage
author {
name
}
}
... on Comment {
id
content
post {
title
}
}
}
facets {
name
values {
key
count
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
性能优化 #
查询复杂度 #
text
┌─────────────────────────────────────────────────────────────┐
│ 查询复杂度控制 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 复杂度计算示例: │
│ │
│ query { │
│ users(first: 10) { # 10 users │
│ posts(first: 5) { # 10 * 5 = 50 posts │
│ comments(first: 3) { # 50 * 3 = 150 comments │
│ content │
│ } │
│ } │
│ } │
│ } │
│ │
│ 总复杂度 = 10 * 5 * 3 = 150 │
│ │
│ 建议: │
│ - 限制嵌套深度 │
│ - 限制每层数量 │
│ - 使用复杂度分析中间件 │
│ │
└─────────────────────────────────────────────────────────────┘
批量加载(DataLoader) #
解决 N+1 查询问题:
javascript
const DataLoader = require('dataloader');
const userLoader = new DataLoader(async (ids) => {
const users = await getUsersByIds(ids);
return ids.map(id => users.find(user => user.id === id));
});
const resolvers = {
Post: {
author: (post) => userLoader.load(post.authorId)
}
};
下一步 #
现在你已经掌握了 GraphQL 查询操作的各种技巧,接下来学习 变更操作详解,学习如何修改数据!
最后更新:2026-03-29