Docs
搜索⌘ K
  • 主页
  • 关于 The Graph
  • 支持的网络
  • 协议合约
  • 子图
    • 子流
      • 代币 API
        • AI Suite
          • 索引
            • 资源
              子图 > 开发 > 创建

              14 分钟

              GraphQL 模式

              概述

              您的子图的模式位于文件 schema.graphql。GraphQL模式是使用GraphQL 接口定义语言定义的。

              注意:如果您从未写过GraphQL模式,建议您在GraphQL类型系统上查看此初级读物。 GraphQL模式的参考文档可以在 GraphQL API部分找到。

              定义实体

              在定义实体之前,重要的是回头一步,思考你的数据是如何架构和联系的。

              • 所有查询都将根据子图模式定义的数据模型进行。 因此,子图模式的设计应通知您的应用程序需要执行的查询。
              • 将实体想象成“含有数据的对象”,而不是作为事件或功能,可能是有用的。
              • 您在 schema.graphql 中定义实体类型, Graph节点将生成顶级字段以查询该实体类型的单个实例和集合。
              • 每一类型的实体都需要使用 @entity 指令注明。
              • 默认情况下,实体是可变的,意味着映射可以加载现有实体,修改它们并存储该实体的新版本。
                • 易燃性是以一种价格计算的,对于那些永远不会被修改的实体类型,例如那些载有从链中逐字提取的数据的类型, 建议用@entity(immutable:true)标记为不可变的。
                • 如果在创建实体的同一区块中发生更改,则映射可以对不可变的实体进行更改。 不可变的实体可以更快地撰写和查询,以便在可能的情况下使用。

              好示例

              下面的 Gravatar 实体围绕 Gravatar 对象构建,是如何定义实体的一个很好的示例。

              1type Gravatar @entity {2  id: Id!3  owner: Bytes4  displayName: String5  imageUrl: String6  accepted: Boolean7}

              坏榜样

              下面的示例中,GravatarAccepted 和 GravatarDeclined 实体都基于事件。 不建议将事件或函数调用以 1:1 的方式映射到实体。

              1type GravatarAccepted @entity {2  id: Bytes!3  owner: Bytes4  displayName: String5  imageUrl: String6}78type GravatarDeclined @entity {9  id: Bytes!10  owner: Bytes11  displayName: String12  imageUrl: String13}

              可选和必选字段

              实体字段可以定义为必填字段或可选字段。在模式中,所需字段以 ! 标明。 如果字段是缩放字段,当您尝试存储实体时会出现错误。 如果字段引用了另一个实体,你就会得到这个错误:

              1Null value resolved for non-null field 'name'

              每个实体必须有一个 id 字段,其类型必须是 Bytes!或者String!。通常建议使用Bytes!,除非 id 包含人类可读的文本,因为有Bytes! id的实体比使用String!``id的写入和查询速度会更快。id 字段充当主钥,并且需要在同一类型的所有实体中是唯一的。由于历史原因,类型 ID!也被接受,是 String!的同义词。

              对于Bytes!的某些实体类型,id 是由另外两个实体的 id 构成的; 这可以使用 concat,例如,let id = left.id.concat(right.id) 来从left和right的 id 构成 id。类似地,要从现有实体的 id 和count构造 id,可以使用 let id = left.id.concatI32(count) 。只要left的长度对于所有这样的实体都是相同的,这种串联就一定会产生唯一的 id,例如,因为 left.id是一个 Address。

              内置标量类型

              GraphQL 支持的标量

              GraphQL API支持以下缩写:

              类型描述
              Bytes字节数组,表示为十六进制字符串。 通常用于以太坊hash和地址。
              Stringstring值的标量。不支持空字符,将被自动删除。
              Booleanboolean 值的标量。
              IntGraphQL spec定义Int为一个带符号的32位整数。
              Int8一个8字节有符号整数,也称为64位有符号整数,可以存储从-9,223,372,036,854,775,808到9,223,372,036,854,775,807的范围内的值。建议使用此类型来表示以太坊中的i64。
              BigInt大整数。 用于以太坊的 uint32, int64, uint64, …, uint256 类型。 注意:uint32以下的所有类型,例如int32, uint24或int8都表示为i32。
              BigDecimalBigDecimal表示为有效数字和指数的高精度小数。 指数范围是 -6143 到 +6144。 四舍五入到 34 位有效数字。
              Timestamp它是一个微秒的i64值。通常用于时间序列和聚合的时间戳字段。

              枚举类型

              您还可以在模式中创建枚举类型。 枚举类型具有以下语法:

              1enum TokenStatus {2  OriginalOwner3  SecondOwner4  ThirdOwner5}

              在模式中定义枚举后,您可以使用枚举值的字符串表示形式在实体上设置枚举字段。 例如,您可以将 tokenStatus 设置为 SecondOwner,方法是首先定义您的实体,然后使用 entity.tokenStatus = "SecondOwner" 设置字段。 下面的示例演示了带有枚举字段的 Token 实体:

              在GraphQL文档⁠中找到更多关于写入编码的详细信息。

              实体关系

              一个实体可能与模式中的一个或多个其他实体发生联系。 您可以在您的查询中遍历这些联系。 The Graph 中的联系是单向的。 可以通过在关系的任一“端”上定义单向关系来模拟双向关系。

              关系是在实体上定义的,就像任何其他字段一样,除了指定的类型是另一个实体类型。

              一对一关系

              定义一个 Transaction 实体类型,该类型与一个 TransactionRecipt 实体类型是可选的一对一的关系:

              1type Transaction @entity(immutable: true) {2  id: Bytes!3  transactionReceipt: TransactionReceipt4}56type TransactionReceipt @entity(immutable: true) {7  id: Bytes!8  transaction: Transaction9}

              一对多关系

              定义一个 TokenBalance 实体类型,它与代币实体类型具有必备的一对多的关系:

              1type Token @entity(immutable: true) {2  id: Bytes!3}45type TokenBalance @entity {6  id: Bytes!7  amount: Int!8  token: Token!9}

              反向查找

              反向查找可以通过 @arotovedFrom 字段定义的实体。 这将在实体上创建一个虚拟字段,可以查询,但不能通过Mappings API手动设置。 相反,它产生于与其他实体界定的关系。 对于这种关系来说,把双方都放在一起是很不合理的。 如果只存储一方而得出另一方,则索引和查询性能都会更好。

              对于一对多的关系,这种关系应该始终保存在’one’一边,而’many’一边应该总是被派生出来的。 以这种方式存储关系,而不是将一系列实体存储在’many’侧, 用于索引和查询Subgraph的性能将会大大提高。 一般而言,应尽量避免储存实体阵列。

              示例

              我们可以从 tokenBalances 中产生一个 `tokenBalances ’ 字段来获取代币:

              1type Token @entity(immutable: true) {2  id: Bytes!3  tokenBalances: [TokenBalance!]! @derivedFrom(field: "token")4}56type TokenBalance @entity {7  id: Bytes!8  amount: Int!9  token: Token!10}

              下面是如何为具有反向查找的子图撰写映射的示例:

              1let token = new Token(event.address) // Create Token2token.save() // tokenBalances is derived automatically34let tokenBalance = new TokenBalance(event.address)5tokenBalance.amount = BigInt.fromI32(0)6tokenBalance.token = token.id // Reference stored here7tokenBalance.save()

              多对多关系

              对于多对多关系,例如每个可能属于任意数量的组织的用户,对关系建模的最直接,但通常不是最高效的方法,是在所涉及的两个实体中的每一个中定义数组。 如果关系是对称的,则只需要存储关系的一侧联系,就可以导出另一侧。

              示例

              定义从User实体类型向Organization实体类型的反向查找。 在下面的例子中,实现这个目标的方法是在 Organization 实体内查找 members 属性。 在查询时,User上的 organization 字段将通过找到所有包含用户ID的 Organization 实体来解决。

              1type Organization @entity {2  id: Bytes!3  name: String!4  members: [User!]!5}67type User @entity {8  id: Bytes!9  name: String!10  organizations: [Organization!]! @derivedFrom(field: "members")11}

              存储这种关系的更加有效的方法是通过一个映射表,这个表为每一个 ’ User’ / ’ Organization’ 配对提供一个条目和一个类似的模式:

              1type Organization @entity {2  id: Bytes!3  name: String!4  members: [UserOrganization!]! @derivedFrom(field: "organization")5}67type User @entity {8  id: Bytes!9  name: String!10  organizations: [UserOrganization!] @derivedFrom(field: "user")11}1213type UserOrganization @entity {14  id: Bytes! # Set to `user.id.concat(organization.id)`15  user: User!16  organization: Organization!17}

              这种方法要求查询下降一个额外的级别来检索,例如,用户的组织:

              1query usersWithOrganizations {2  users {3    organizations {4      # this is a UserOrganization entity5      organization {6        name7      }8    }9  }10}

              这种存储多对多关系的更精细的方式,将导致为子图存储的数据更少,因此,子图的索引和查询速度通常会大大加快。

              向模式添加注释

              根据 GraphQL 规范,可以使用双引号#在模式实体属性上方添加注释。 这在下面的示例中进行了说明:

              1type MyFirstEntity @entity {2  # unique identifier and primary key of the entity3  id: Bytes!4  address: Bytes!5}

              定义全文搜索字段

              全文搜索查询根据文本搜索输入来过滤和排列实体。 通过在与索引文本数据进行比较之前,将查询文本输入处理到词干中,全文查询能够返回相似词的匹配项。

              全文查询定义包括查询名称、用于处理文本字段的语言词典、用于对结果进行排序的排序算法,以及搜索中包含的字段。 每个全文查询可能跨越多个字段,但所有包含的字段必须来自单个实体类型。

              要添加全文查询,请在 GraphQL 模式中包含带有全文指令的 _Schema_ 类型。

              1type _Schema_2  @fulltext(3    name: "bandSearch"4    language: en5    algorithm: rank6    include: [{ entity: "Band", fields: [{ name: "name" }, { name: "description" }, { name: "bio" }] }]7  )89type Band @entity {10  id: Bytes!11  name: String!12  description: String!13  bio: String14  wallet: Address15  labels: [Label!]!16  discography: [Album!]!17  members: [Musician!]!18}

              示例bandSearch 字段可以用来在查询中根据name、description、和bio字段中的文本文档过滤Band 实体。 跳转到GraphQL API - 查询以了解全文搜索 API 和更多示例用法。

              1query {2  bandSearch(text: "breaks & electro & detroit") {3    id4    name5    description6    wallet7  }8}

              **特征管理:**从 specVersion 0.0.4 及以后, fullTextSearch 必须在子图清单中features 部分下申报。

              支持的语言

              选择不同的语言将对全文搜索 API 产生明确的(尽管有时是微妙的)影响。 全文查询字段涵盖的字段将会在所选语言的内容中进行检查,因此分析和搜索查询产生的词位因语言而异。 例如:当使用支持的土耳其语词典时,“token”的词干为“toke”,而英语词典当然会认为其词干为“token”。

              支持的语言词典:

              代码词典
              simple通用
              da丹麦语
              nl荷兰语
              en英语
              fi芬兰语
              frFrench
              de德语
              hu匈牙利语
              it意大利语
              no挪威语
              pt葡萄牙语
              ro罗马尼亚语
              ru俄语
              es西班牙语
              sv瑞典语
              tr土耳其语

              排序算法

              支持的排序结果算法:

              算法说明
              排名使用全文查询的匹配质量 (0-1) 对结果进行排序。
              proximityRank与 rank 类似,但也包括匹配的接近程度。
              ⁠在GitHub上编辑⁠

              子图清单Writing AssemblyScript Mappings
              在此页面上
              • 概述
              • 定义实体
              • 内置标量类型
              • 枚举类型
              • 实体关系
              • 反向查找
              • 向模式添加注释
              • 定义全文搜索字段
              • 支持的语言
              • 排序算法
              The GraphStatusTestnetBrand AssetsForum安全Privacy PolicyTerms of Service