GraphQL API
Reading time: 14 min
This guide explains the GraphQL Query API that is used for The Graph Protocol.
在您的子图模式中,定义了称为 Entities
的类型。 对于每个 Entity
类型,将在顶级 Query
类型上生成一个 entity
和 entities
字段。 请注意,使用Graph 时,query
不需要包含在 graphql
查询的顶部。
查询模式中定义的单个 Token
实体:
{token(id: "1") {idowner}}
**注意:**查询单个实体时,id
字段为必填项,而且必须为字符串。
查询所有 Token
实体:
{tokens {idowner}}
查询集合时,orderBy
参数可用于按特定属性排序。 此外,orderDirection
可用于指定排序方向,asc
用于升序,而desc
用于降序。
{tokens(orderBy: price, orderDirection: asc) {idowner}}
在以下示例中,我们根据代币所有者的名称对其进行排序:
{tokens(orderBy: owner__name, orderDirection: asc) {idowner {name}}}
查询集合时,可以使用 first
参数从集合的开头进行分页。 值得注意的是,默认排序顺序是按 ID 以字母数字升序排列,而不是按创建时间排列。
此外,skip
参数可用于跳过实体和分页。 例如 first:100
显示前 100 个实体,first:100, skip:100
显示接下来的 100 个实体。
查询应该避免使用非常大的 skip
值,因为它们通常性能表现不佳。 要检索大量项目,最好根据上一个示例中所示的属性对实体进行分页。
查询前10 个代币:
{tokens(first: 10) {idowner}}
要查询集合中间的实体组,skip
参数可以与 first
参数结合使用,以跳过集合开头的指定数量实体。
查询从集合开头偏移 10 个位置的 10 个Token
实体:
{tokens(first: 10, skip: 10) {idowner}}
如果客户端需要检索大量实体,则基于属性进行查询和过滤会明显提高性能。 例如,客户端可以使用以下查询检索大量代币:
query manyTokens($lastID: String) { tokens(first: 1000, where: { id_gt: $lastID }) {idowner}}}
第一次,它会发送带有 lastID = ""
的查询,对于后续请求,会将 lastID
设置为上一个请求中的最后一个实体的id
属性。 与简单的提高 skip
值相比,这种方法的性能要好得多。
您可以在查询中使用 where
参数来过滤不同的属性。 您可以在 where
参数内过滤多个值。
查询包含failed
属性的challenges 的 结果:
{challenges(where: { outcome: "failed" }) {challengeroutcomeapplication {id}}}
您可以使用 _gt
、_lte
等后缀进行值比较:
{applications(where: { deposit_gt: "10000000000" }) {idwhitelisteddeposit}}
您还可以通过 _ change _ block (number _ gte: Int)
过滤实体-这个过滤器在指定的区块中或之后更新的实体。
如果您只想获取已经更改的实体,例如自上次轮询以来改变的实体,那么这将非常有用。或者也可以调查或调试子图中实体的变化情况(如果与区块过滤器结合使用,则只能隔离在特定区块中发生变化的实体)。
{applications(where: { _change_block: { number_gte: 100 } }) {idwhitelisteddeposit}}
可以在带 _
后缀的字段中基于嵌套实体进行筛选。
如果您希望只获取其子级实体满足条件的实体,那么这可能很有用。
{challenges(where: { application_: { id: 1 } }) {challengeroutcomeapplication {id}}}
从Graph 节点 版本开始,您可以在同一where
参数中对多个参数进行分组,使用and``or
运算符根据多个标准筛选结果。
在下面的示例中,我们正在筛选outcome``succeeded
且number
大于或等于100
的挑战。
{challenges(where: { and: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {challengeroutcomeapplication {id}}}
**语法糖:**您可以通过传递一个用逗号分隔的子表达式来删除and
运算符,从而简化上述查询。
{challenges(where: { number_gte: 100, outcome: "succeeded" }) {challengeroutcomeapplication {id}}}
在下面的示例中,我们正在筛选outcome``succeeded
或number
大于或等于100
的挑战。
{challenges(where: { or: [{ number_gte: 100 }, { outcome: "succeeded" }] }) {challengeroutcomeapplication {id}}}
注意:在构造查询时,重要的是要考虑使用or
运算符对性能的影响。虽然or
可能是扩大搜索结果的有用工具,但它也可能有巨大的成本。or
的主要问题之一是它可能会导致查询速度减慢。这是因为or
需要数据库扫描多个索引,这可能是一个耗时的过程。为了避免这些问题,建议开发人员尽可能使用和运算符而不是或。这允许更精确地过滤,并可以导致更快、更准确的查询。
参数后缀的完整列表:
__not_gt_lt_gte_lte_in_not_in_contains_contains_nocase_not_contains_not_contains_nocase_starts_with_starts_with_nocase_ends_with_ends_with_nocase_not_starts_with_not_starts_with_nocase_not_ends_with_not_ends_with_nocase
请注意,某些后缀仅支持特定类型。 例如,Boolean
仅支持 _not
、_in
和 _not_in
,但是_
只适用于对象和接口类型。。
此外,以下全局过滤器作为 where
参数的一部分可用:
_change_block(number_gte: Int)
您可以查询实体的状态,不仅查询默认的最新区块,还可以查询过去的任意区块。通过在查询的顶级字段中包含block
参数,可以通过区块号或区块哈希指定应该发生查询的区块。
这种查询结果不会随着时间的推移而改变,即对过去某个区块的查询,无论何时执行,都将返回相同的结果。唯一的例外是,如果您在非常靠近链头的区块上进行查询,如果该区块不在主链上,并且链被重新组织,则结果可能会改变。 一旦一个区块被确认是最终的区块,那么查询的结果就不会改变。
请注意,当前的实现仍然受到某些限制,这些限制可能会违反这些保证。该实现不能总是判断给定的区块哈希根本不在主链上,或者对于一个不能被认为是最终的区块,逐块哈希查询的结果可能会受到与查询同时运行的区块重组的影响。当区块是最终区块并且已知在主链上时,它们不会影响区块哈希查询的结果。问题详细解释了这些限制是什么。
{challenges(block: { number: 8000000 }) {challengeroutcomeapplication {id}}}
此查询将返回 Challenge
实体及其关联的 Application
实体,因为它们在处理第 8000000 区块后就存在了。
{challenges(block: { hash: "0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c" }) {challengeroutcomeapplication {id}}}
此查询将返回 Challenge
实体及其关联的 Application
实体,因为它们在处理具有给定哈希值的区块后就存在了。
全文搜索查询字段提供了一个表达性的文本搜索 API,可以添加到子图模式中并进行自定义。 请参阅以将全文搜索添加到您的子图中。
全文搜索查询有一个必填字段 text
,用于提供搜索词。 在这个 text
搜索字段中可以使用几个特殊的全文运算符。
全文搜索运算符:
符号 | 运算符 | 描述 |
---|---|---|
& | And | 用于将多个搜索词组合到包含所有提供词条的实体的过滤器中 |
| | Or | 由 or 运算符分隔的多个搜索词的查询,将返回与任何提供的词匹配的所有实体 |
<-> | Follow by | 指定两个单词之间的距离。 |
:* | Prefix | 使用前缀搜索词查找前缀匹配的单词(需要 2 个字符) |
使用 or
运算符,此查询将过滤到在其全文字段中具有“anarchism”或“crumpet”变体的 blog 实体。
{blogSearch(text: "anarchism | crumpets") {idtitlebodyauthor}}
follow by
运算符指定全文文档中相隔特定距离的单词。 以下查询将返回所有“decentralize”后跟着“philosophy”变体的日志。
{blogSearch(text: "decentralized <-> philosophy") {idtitlebodyauthor}}
可以将全文运算符进行组合来制作更复杂的过滤器。 在下面的查询示例中,使用前缀搜索运算符与其他运算符的结合,可以实现匹配所有以“lou”开头后,跟着“music”单词的日志实体。
{blogSearch(text: "lou:* <-> music") {idtitlebodyauthor}}
Graph Node使用对其接收的GraphQL查询进行的验证,该工具基于。验证规则失败的查询会出现标准错误-请访问了解更多信息。
GraphQL模式通常定义查询
、订阅
和突变
的根类型。Graph仅支持查询
。子图的根查询
类型是从子图清单中包含的GraphQL模式自动生成的。
**注意:**我们的 API 不提供对变种的支持,因为开发人员会从他们的应用程序中直接针对底层区块链发出交易。
模式定义中所有带有 @entity
指示的 GraphQL 类型都将被视为实体,并且必须具有 ID
字段。
注意: 目前,模式定义中的所有类型都必须具有 @entity
指示。 将来,我们会将没有 @entity
指示的类型视为值对象,但目前尚不支持。
所有子图都有一个自动生成的_Meta_
对象,它提供对子图元数据的访问。可按如下方式查询:
{_meta(block: { number: 123987 }) {block {numberhashtimestamp}deploymenthasIndexingErrors}}
如果提供了区块,则元数据为该区块的元数据,如果未使用最新的索引区块。如果提供,则区块必须在子图的起始区块之后,并且小于或等于最近索引的区块。
deployment
是一个唯一的ID,对应于subgraph.yaml
文件的IPFS CID。
block
提供有关最新区块的信息(考虑传递给_meta
的任何区块约束):
- hash:区块的哈希
- number:区块编号
- timestamp:区块的时间戳(如果可用)(当前仅适用于索引EVM网络的子图)
hasIndexingErrors
是一个布尔值,用于标识子图在过去的某个区块中是否遇到索引错误。