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

                  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