14 分钟
GraphQL API
了解在The Graph中使用的 GraphQL 查询 API。
什么是GraphQL?
GraphQL是API的查询语言,也是用您现有数据执行这些查询的运行时间。The Graph使用GraphQL查询子图。
要理解GraphQL所起的更大作用,请查看 developing 和 创建一个子图。
用GraphQL查询
在你的子图模式中,定义了叫做Entities
的类型。对于每个Entity
类型,entity
和 entities
字段将生成在顶级Query
类型上。
注意:在使用The Graph时,query
不需要包含在graphql
查询的顶部。
例子
查询在您的模式中定义的单个Token
实体:
1{2 token(id: "1") {3 id4 owner5 }6}
注意:当查询单个实体时,需要填写id
字段,它必须是一个字符串。
查询所有 Token
实体:
1{2 tokens {3 id4 owner5 }6}
排序
查询集合时,您可以:
- 使用
orderBy
参数按特定属性排序。 - 使用
orderDirection
来指定排序方向,asc
用于升序或desc
用于降序。
示例
1{2 tokens(orderBy: price, orderDirection: asc) {3 id4 owner5 }6}
嵌套实体筛选示例
从Graph节点v0.30.0
可以根据嵌套实体排序。
在以下示例中,我们根据代币所有者的名称对其进行排序:
1{2 tokens(orderBy: owner__name, orderDirection: asc) {3 id4 owner {5 name6 }7 }8}
目前,您可以在 @entity
和 @orotovedFrom
字段按一级深度String
或 ID
类型排序。 不幸的是,按一个深度实体的接口排序,仍不支持按数组和嵌套实体的字段排序。
分页
当查询集合时,最好:
- 从集合开始使用
first
参数分页。- 默认排序顺序是
ID
,按字母和数字顺序排列,不是创建时间。
- 默认排序顺序是
- 使用
skip
参数跳过实体和分页。例如,first:100
会显示前100个实体,first:100, skip:100
会显示后100个实体。 - 避免在查询中使用
skip
值,因为它们通常表现很差。 要检索大量条目,最好是通过上面示例中显示的属性的实体进行查找。
使用 first
示例
查询前10 个代币:
1{2 tokens(first: 10) {3 id4 owner5 }6}
查询集合中间的实体群组, skip
参数可以与 first
参数一起使用,以跳过从集合开始的指定数量的实体。
使用 first
和 skip
的示例
查询 10 Token
实体,由集合开始时的10个地方抵消:
1{2 tokens(first: 10, skip: 10) {3 id4 owner5 }6}
使用 first
和 id_ge
的示例
如果客户端需要检索大量实体,则基于属性进行查询和过滤会明显提高性能。 例如,客户端可以使用以下查询检索大量代币:
1query manyTokens($lastID: String) { tokens(first: 1000, where: { id_gt: $lastID }) {2 id3 owner4 }5 }6}
第一次,它会用’lastID = ""发送查询, 对于随后的请求,它会在上次请求中将
lastID设置为最后一个实体的
id属性。 这个方法将大大优于使用增加
skip`值。
过滤
- 您可以在查询中使用
where
参数来过滤不同的属性。 - 您可以在
where
参数中筛选多个值。
使用 where
的示例
使用 ‘失败的’ 结果查询挑战:
1{2 challenges(where: { outcome: "failed" }) {3 challenger4 outcome5 application {6 id7 }8 }9}
你可以使用后缀,例如_gt
, _lte
来进行值比较:
范围过滤示例
1{2 applications(where: { deposit_gt: "10000000000" }) {3 id4 whitelisted5 deposit6 }7}
区块过滤示例
您也可以筛选在指定的区块中或之后更新的实体使用 _change_block(number_gte: Int)
。
如果您只想获取已经更改的实体,例如自上次轮询以来改变的实体,那么这将非常有用。或者也可以调查或调试子图中实体的变化情况(如果与区块过滤器结合使用,则只能隔离在特定区块中发生变化的实体)。
1{2 applications(where: { _change_block: { number_gte: 100 } }) {3 id4 whitelisted5 deposit6 }7}
嵌套实体筛选示例
在后缀是`_‘的字段中可以根据嵌套的实体进行过滤。
如果您希望只获取其子级实体满足条件的实体,那么这可能很有用。
1{2 challenges(where: { application_: { id: 1 } }) {3 challenger4 outcome5 application {6 id7 }8 }9}
逻辑运算符
对于Graph节点v0.30.0
,您可以在同一个where
参数中使用and
或or
运算符,根据多个标准过滤结果。
AND
运算符
下面的示例对大于或等于100
的outcome
、successed
和number
的挑战进行过滤。
1{2 challenges(where: { and: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {3 challenger4 outcome5 application {6 id7 }8 }9}
Synteracc sugar: 你可以通过传递一个用逗号分隔的子表达式来移除and
运算符来简化上述查询。
1{2 challenges(where: { number_gte: 100, outcome: "succeeded" }) {3 challenger4 outcome5 application {6 id7 }8 }9}
OR
运算符
下面的示例对大于或等于100
的outcome
、successed
和number
的挑战进行过滤。
1{2 challenges(where: { or: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {3 challenger4 outcome5 application {6 id7 }8 }9}
注意:在构建查询时,重要的是要考虑使用or
运算符的性能影响。 虽然or
可以成为扩大搜索结果的一个有用工具,但它也可能有很高的费用。 or
的主要问题之一是它可能导致查询减缓。 这是因为or
需要数据库通过多个索引进行扫描,这可能是一个耗时的过程。 为了避免这些问题,建议开发人员使用和操作人员,而不是在任何可能的情况下使用。 这样可以进行更精确的过滤,可以更快、更准确的查询。
所有过滤器
参数后缀的完整列表:
1_2_not3_gt4_lt5_gte6_lte7_in8_not_in9_contains10_contains_nocase11_not_contains12_not_contains_nocase13_starts_with14_starts_with_nocase15_ends_with16_ends_with_nocase17_not_starts_with18_not_starts_with_nocase19_not_ends_with20_not_ends_with_nocase
请注意,某些后缀只支持特定类型。 例如,Boolean
只支持 _not
、_in
和_not_in
,但_
只适用于对象和接口类型。
此外,下列全局过滤器可以作为where
参数的一部分:
1_change_block(number_gte: Int)
跨时间查询
您可以查询您的实体状态,不仅仅是为了最新的区块, 它是默认的,但也是过去的任意区块的。 可以在查询的顶级字段中包含一个 ’ block’ 参数来指定查询的要么用其区块编号或区块哈希。
这种查询结果不会随着时间的推移而改变,即对过去某个区块的查询,无论何时执行,都将返回相同的结果。唯一的例外是,如果您在非常靠近链头的区块上进行查询,如果该区块不在主链上,并且链被重新组织,则结果可能会改变。 一旦一个区块被确认是最终的区块,那么查询的结果就不会改变。
请注意,当前的实现仍然受到某些限制,这些限制可能会违反这些保证。该实现不能总是判断给定的区块哈希根本不在主链上,或者对于一个不能被认为是最终的区块,逐块哈希查询的结果可能会受到与查询同时运行的区块重组的影响。当区块是最终区块并且已知在主链上时,它们不会影响区块哈希查询的结果。这个问题详细解释了这些限制是什么。
示例
1{2 challenges(block: { number: 8000000 }) {3 challenger4 outcome5 application {6 id7 }8 }9}
此查询将返回 Challenge
实体及其关联的 Application
实体,因为它们在处理8,000,000个区块后就存在了。
示例
1{2 challenges(block: { hash: "0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c" }) {3 challenger4 outcome5 application {6 id7 }8 }9}
此查询将返回 Challenge
实体及其关联的 Application
实体,因为它们在处理具有给定哈希值的区块后就存在了。
全文搜索查询
全文搜索查询字段提供了一个表达性的文本搜索 API,可以添加到子图模式中并进行自定义。 请参阅定义全文搜索字段以将全文搜索添加到您的子图中。
全文搜索查询有一个必填字段 text
,用于提供搜索词。 在这个 text
搜索字段中可以使用几个特殊的全文运算符。
全文搜索运算符:
符号 | 运算符 | 描述 |
---|---|---|
& | And | 用于将多个搜索词组合到包含所有提供词条的实体的过滤器中 |
| | Or | 由 or 运算符分隔的多个搜索词的查询,将返回与任何提供的词匹配的所有实体 |
<-> | Follow by | 指定两个单词之间的距离。 |
:* | Prefix | 使用前缀搜索词查找前缀匹配的单词(需要 2 个字符) |
例子
使用 or
运算符,这个查询将过滤到在其全文字段中具有”anarchism” or “crumpet”变化的博客实体。
1{2 blogSearch(text: "anarchism | crumpets") {3 id4 title5 body6 author7 }8}
follow by
运算符指定全文文档中相隔特定距离的单词。 以下查询将返回所有“decentralize”后跟着“philosophy”变体的日志。
1{2 blogSearch(text: "decentralized <-> philosophy") {3 id4 title5 body6 author7 }8}
可以将全文运算符进行组合来制作更复杂的过滤器。 在下面的查询示例中,使用前缀搜索运算符与其他运算符的结合,可以实现匹配所有以“lou”开头后,跟着“music”单词的日志实体。
1{2 blogSearch(text: "lou:* <-> music") {3 id4 title5 body6 author7 }8}
验证
Graph节点实现使用 graphql-tools-rs验证它收到的 GraphQL 查询的 specification-based 验证基于 graphql-js 参考实现。 查询失败的验证规则有一个标准错误 - 请访问 GraphQL spec来了解更多信息。
模式
您的数据源模式,例如可用于查询的实体类型、值和关系是通过 GraphQL 接口定义语言(IDL)定义的。
GraphQL模式通常定义查询
、订阅
和突变
的根类型。The Graph仅支持查询
。子图的根查询
类型是从子图清单中包含的GraphQL模式自动生成的。
注意:我们的 API 不提供对突变的支持,因为开发人员会从他们的应用程序中直接针对底层区块链发出交易。
实体
模式定义中所有带有 @entity
指示的 GraphQL 类型都将被视为实体,并且必须具有 ID
字段。
注意: 目前,您的模式中的所有类型都必须有一个 @entity
指令。 今后,我们将把没有@entity
指令的类型视为值对象,但这还不被支持。
子图元数据
所有子图都有一个自动生成的_Meta_
对象,它提供对子图元数据的访问。可按如下方式查询:
1{2 _meta(block: { number: 123987 }) {3 block {4 number5 hash6 timestamp7 }8 deployment9 hasIndexingErrors10 }11}
如果提供了区块,则元数据为该区块的元数据,如果未使用最新的索引区块。如果提供,则区块必须在子图的起始区块之后,并且小于或等于最近索引的区块。
deplement
是一个唯一的ID,与 subgraph.yaml
文件的 IPFS CID 相对应。
block
提供了关于最新区块的信息(同时考虑到传递给_meta
的任何区块约束):
- hash:区块的哈希
- number:区块编号
- timestamp:区块的时间戳,如果可用的话(当前仅适用于索引EVM网络的子图)
hasIndexingErrors
是一个布尔值,用于标识子图在过去的某个区块中是否遇到索引错误。