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

GraphQL mutation是否无需先查询ID即可关联已有记录?

GraphQL Mutation 关联已有对象的疑问解答

我是一名业余开发者,正在学习GraphQL(有基础SQL知识,曾用SQLite搭建家庭应用,完成过数据增删改查和关联操作)。用Hasura构建数据库表关系模式的体验很棒,查询变得特别简单。不过在学习GraphQL数据变更(mutation)时,有个疑问想弄明白:

我要插入一条用户(John Brown)的记录,这个用户自2003年起就职于ibm公司,用户和公司分属不同表。当前用的mutation语句是:

mutation MyMutation {
  insert_users(objects: 
  { 
    user_company: { data: { name: "ibm", date: 2003 } }, 
    first_name: "John", last_name: "Brown" 
}) 
{
    returning {
      id
    }
  }
}

这条语句能正常执行,但每次都会创建新的John Brown用户和ibm公司记录。我的问题是:

  1. GraphQL是否要求必须先查询目标记录的ID(类似SQL操作)?
  2. 是否存在GraphQL机制可实现「若指定数据的对象已存在,则复用该对象建立关联而非创建新对象」?

问题解答

1. GraphQL是否必须先查询目标ID?

GraphQL本身没有强制要求必须先查目标记录ID,这取决于你用的服务端实现(比如你用的Hasura)。你当前用的user_company: { data: {...} }是Hasura的创建关联对象语法,默认会生成新的公司记录。如果要关联已有公司,确实需要先拿到公司的唯一标识(比如ID),然后用Hasura的关联已有对象语法——用connect字段替代data字段。

比如先查询ibm公司的ID:

query GetCompanyId {
  companies(where: {name: {_eq: "ibm"}, date: {_eq: 2003}}) {
    id
  }
}

再用查到的ID关联插入用户:

mutation InsertUser {
  insert_users(objects: {
    first_name: "John",
    last_name: "Brown",
    user_company: { connect: { id: 123 } } # 替换为实际查询到的ID
  }) {
    returning {
      id
    }
  }
}

这本质和SQL里先查ID再关联的逻辑一致,但不是GraphQL的通用规则,只是Hasura这类工具的具体实现方式。

2. 是否存在复用已有对象的机制?

当然有,在Hasura里可以通过**upsert(插入或更新)**结合关联的upsert语法实现,不用手动拆分查询和插入步骤。

首先需要给companies表的name和date字段设置联合唯一约束(因为这两个字段的组合能唯一标识公司记录),然后在mutation里使用on_conflict参数:

mutation InsertUserWithCompanyUpsert {
  insert_users(objects: {
    first_name: "John",
    last_name: "Brown",
    user_company: {
      data: {
        name: "ibm",
        date: 2003
      },
      on_conflict: {
        constraint: companies_name_date_key, # 替换为你设置的唯一约束名称
        update_columns: [] # 冲突时不更新任何字段,直接复用已有记录
      }
    }
  }) {
    returning {
      id
      user_company {
        id
        name
      }
    }
  }
}

这个mutation的逻辑是:如果name="ibm"且date=2003的公司记录已存在,就直接关联该记录;如果不存在,就创建新的公司记录再关联。

如果还要避免重复创建John Brown用户,同样给users表的first_name和last_name设置联合唯一约束,再加上用户自身的on_conflict处理:

mutation UpsertUserWithCompany {
  insert_users(objects: {
    first_name: "John",
    last_name: "Brown",
    user_company: {
      data: {
        name: "ibm",
        date: 2003
      },
      on_conflict: {
        constraint: companies_name_date_key,
        update_columns: []
      }
    }
  },
  on_conflict: {
    constraint: users_first_name_last_name_key,
    update_columns: [user_company_id] # 冲突时可选择更新关联的公司ID
  }) {
    returning {
      id
      user_company {
        id
        name
      }
    }
  }
}

这种机制和SQL里的INSERT ... ON CONFLICT逻辑完全对应,Hasura把它封装成了GraphQL语法,简化了操作流程。


内容的提问来源于stack exchange,提问作者WoJ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:33:26