定義實體(Defining Entities)
schema.graphql 文件定義了各種 GraphQL 架構。 由于 GraphQL 查詢語言的工作方式,模式文件本質上決定了來自 SubQuery 的數據的形狀, 要了解有關如何使用 GraphQL 架構語言編寫的更多資訊,我們建議查看架構和類型(https://graphql.org/learn/schema/#type-language)
重要提示:當您對架構文件(schema file)進行任何更改時,請確保使用 yarn codegen 代碼來生成重新生成類型目錄,
實體(Entities)
每個實體(entity)都必須定義它的必填字段id與ID的類型!它用作主鍵,并且在所有相同類型的實體中是唯一的。
實體(entity)中不可為空的字段由“ ! ”來表示。 請看下面的例子:
type Example @entity { id: ID! # id field is always required and must look like this name: String! # This is a required field address: String # This is an optional field }
支持的標量和類型(Supported scalars and types)
我們目前支持流動標量類型:
• ID
• Int
• String
• BigInt
• Date
• Boolean
•
• JSON 也可以存儲結構化數據,請參閱 JSON 類型(https://doc.subquery.network/create/graphql.html#json-type)。
按非主鍵字段進行索引(Indexing by non-primary-key field)
為了提高查詢性能,只需在非主鍵字段上執行 @index 注釋即可索引實體字段。
但是,我們不允許用戶在任何 JSON 對象上添加 @index 注釋, 默認情況下,索引會自動添加到外鍵和資料庫中的 JSON 字段,但只是為了增強查詢服務性能。
這有一個例子。
type User @entity { id: ID! name: String! @index(unique: true) # unique can be set to true or false title: Title! # Indexes are automatically added to foreign key field } type Title @entity { id: ID! name: String! @index(unique:true) }
假設我們知道這個用戶的名字,但我們不知道確切的 id 值,我們可以在名稱字段后面添加@index,而不是提取所有用戶然后按名稱過濾, 這使得查詢速度更快,我們還可以添加 unique: true 以確保唯一性,
如果字段不唯一,則最大結果集為 100
當代碼生成運行時,這將自動在 User 模型下創建一個 getByName,然后外鍵字段 title 將創建一個 getByTitleId 方法,這兩者都可以在映射函數中直接訪問。
/* Prepare a record for title entity */ INSERT INTO titles (id, name) VALUES (‘id_1’, ‘Captain’)
// Handler in mapping function import {User} from “../types/models/User” import {Title} from “../types/models/Title” const jack = await User.getByName(‘Jack Sparrow’); const captainTitle = await Title.getByName(‘Captain’); const pirateLords = await User.getByTitleId(captainTitle.id); // List of all Captains
實體關系(Entity Relationships)
一個實體(entity)通常與其他實體(entity)有嵌套關系。 默認情況下,將字段值設置為另一個實體(entity)名稱將定義這兩個實體(entity)之間的一對一關系,
可以使用以下示例配置不同的實體(entity)關系(一對一、一對多和多對多)。
- 一對一關系(One-to-One Relationships)
當只有一個實體映射到另一個實體時,一對一關系是默認的,
例子:一本護照只屬于一個人,一個人只有一本護照(在這個例子中):
type Person @entity { id: ID! } type Passport @entity { id: ID! owner: Person! }
或者
type Person @entity { id: ID! passport: Passport! } type Passport @entity { id: ID! owner: Person! }
- 一對多關系(One-to-Many relationships)
您可以使用方括號表示一個字段類型包括多個實體。
示例:一個人可以擁有多個帳戶,
type Person @entity { id: ID! accounts: [Account] } type Account @entity { id: ID! publicAddress: String! }
- 多對多關系(Many-to-Many relationships)
多對多關系可以通過實現一個映射實體(mapping entity)來連接其他兩個實體(entity)來實現。
示例:每個人都是多個組 (PersonGroup) 的一部分,并且組有多個不同的人 (PersonGroup)。
type Person @entity { id: ID! name: String! groups: [PersonGroup] } type PersonGroup @entity { id: ID! person: Person! Group: Group! } type Group @entity { id: ID! name: String! persons: [PersonGroup] }
此外,可以在中間實體(entity)的多個字段中創建同一實體(entity)的連接。
例如,一個賬戶可以實現多次轉賬,每次轉賬都有一個源賬戶和目的地賬戶。
這將通過 Transfer 層在兩個 Accounts(from 和 to)之間建立雙向關系,
type Account @entity { id: ID! publicAddress: String! } type Transfer @entity { id: ID! amount: BigInt from: Account! to: Account! }
反向查找(Reverse Lookups)
為了使一個實體(entity)能夠反向查詢到一個關系,請將 @derivedFrom 附加到該字段并指向另一個實體(entity)的反向查找字段,
這會在可以查詢的實體(entity)上創建一個虛擬字段,
通過將 sentTransfer 或 receivedTransfer 設置為從相應的 from 或 to 字段得出的值,可以從帳戶實體中訪問“來自” 賬戶的轉移。
type Account @entity { id: ID! publicAddress: String! sentTransfers: [Transfer] @derivedFrom(field: “from”) receivedTransfers: [Transfer] @derivedFrom(field: “to”) } type Transfer @entity { id: ID! amount: BigInt from: Account! to: Account! }
JSON 類型(JSON type)
我們支持將數據保存為 JSON 類型(JSON type),這是一種存儲結構化數據的快速方式, 我們將自動生成相應的 JSON 接口來查詢這些數據,并節省您定義和管理實體(entities)的時間。
我們建議用戶在以下場景中使用 JSON 類型:
• 在單個字段中存儲結構化數據比創建多個單獨的實體(entities)更易于管理。
• 保存任意鍵/值用戶首選項(其中值可以是布爾值、文本或數字,并且不用為不同的數據類型設置單獨的列)
• 架構是不穩定的并且經常變化
定義 JSON 指令(Define JSON directive)
通過在實體中添加 jsonField 注釋,將該屬性定義為 JSON 類型, 這將自動為您項目中 types/interfaces.ts 下的所有 JSON 對象生成接口,您也可以在映射函數中訪問它們。
與實體不同,jsonField 指令對象不需要任何 id 字段。 JSON 對象還可以與其他 JSON 對象嵌套。
type AddressDetail @jsonField { street: String! district: String! } type ContactCard @jsonField { phone: String! address: AddressDetail # Nested JSON } type User @entity { id: ID! contact: [ContactCard] # Store a list of JSON objects }
查詢 JSON 字段(Querying JSON fields)
使用 JSON 類型的缺點是過濾時對查詢效率的影響很小,因為每次執行文本搜索時,都是針對整個實體來進行的,
但是,在我們的查詢服務中,影響仍然可以接受。 下面是一個示例,說明如何在 GraphQL 查詢中對 JSON 字段使用 contains 運算符來查找擁有包含“0064”的電話號碼的前 5 個用戶,
#To find the the first 5 users own phone numbers contains ‘0064’. query{ user( first: 5, filter: { contactCard: { contains: [{ phone: “0064” }] } }){ nodes{ id contactCard } } }