Subgraph-Entwicklung, Teil 2: Behandeln von Arrays und Identifizieren von Entitäten

(ProtoFire.io)

(Teil 1) ) | Teil 2

Dieser Blog-Beitrag enthält praktische Empfehlungen zur effizienten Verwendung und Generierung von Arrays Entitäts-IDs, die eindeutig und referenzierbar sind.

In Teil 1 dieser Serie haben wir eine Übersicht über Untergraphen bereitgestellt, um Entwicklern das Verständnis ihrer Grundstruktur zu erleichtern. Darüber hinaus haben wir unsere Erkenntnisse zum Zuordnen und Aggregieren von Daten geteilt.

Dieses Mal werden wir zwei weitere Themen diskutieren: Behandeln von Arrays und Generieren von IDs für Entitäten, die sowohl eindeutig als auch leicht referenzierbar sind. Im Rahmen der Diskussion werden wir unsere Empfehlungen zur effizienten Verwaltung von Arrays und zur korrekten Benennung von Entitäten geben.

Effizienter Umgang mit Arrays

Das Hinzufügen von Arrays zu Entitäten ist in bestimmten Szenarien hilfreich. Es gibt beispielsweise Fälle, in denen wir eine Liste von Adressen für eine Datenquelle modellieren oder historische Änderungen für ein bestimmtes Feld im Laufe der Zeit verfolgen müssen.

Ohne vorherige Kenntnis der Funktionsweise von Arrays in Untergraphen könnten wir dies berücksichtigen Erstellen eines Felds eines Array-Typs in einer Entitätstypdefinition (in der Datei schema.graphql) und Initialisieren eines leeren Arrays, wenn eine neue Entität desselben Typs erstellt wird. Wenn dem Array neue Daten hinzugefügt werden, können wir die Daten pushen und die Entität speichern. Dies klingt zwar intuitiv, funktioniert aber leider nicht.

Das manuelle Behandeln von Arrays in Untergraphen, insbesondere im obigen Szenario, weist einige Einschränkungen auf. Wenn Sie auf ein Array einer Entität zugreifen, erhalten Sie tatsächlich eine Kopie des Arrays. Wenn Sie also neue Daten hinzufügen und die Entität speichern, funktioniert dies nicht wie erwartet, da Sie lediglich eine Kopie des Arrays ändern, während das Original unverändert bleibt.

Zum Aktualisieren Im eigentlichen Array können wir die Kopie des Arrays in eine Variable einfügen und dann die Daten ändern. Als Nächstes können wir die Variable als neues Array für die Entität festlegen. Auf diese Weise wird das alte Array durch die Kopie ersetzt. Dieser Vorgang zum Aktualisieren des Arrays wird im folgenden Code veranschaulicht.

// This won"t work
entity.numbers.push(BigInt.fromI32(1))
entity.save()// This will work
let numbers = entity.numbers
numbers.push(BigInt.fromI32(1))
entity.numbers = numbers
entity.save()

Sie können ein Array zwar auf die oben gezeigte Weise aktualisieren, dies ist jedoch keine ideale Lösung . Abgesehen davon, dass es unpraktisch ist, gibt es einen weiteren Grund, Arrays nicht manuell zu behandeln – Zeitreise-Abfragen. (Lesen Sie Teil 1 der Serie, um mehr über Zeitreise-Abfragen zu erfahren.)

Es ist nur möglich, Zeitreise-Abfragen durchzuführen, da Untergraphen alle Änderungen in allen Entitäten verfolgen, die alle vorhanden sind Zeit. Wenn es viele Entitäten mit Arrayfeldern gibt, die groß sind und häufig aktualisiert werden, müssen auch Kopien aller Arrays gespeichert werden. Dies beeinträchtigt die Leistung und den Speicherplatz eines Indexers, der Ihren Untergraphen indiziert.

Derzeit ist der gehostete Dienst des Diagramms der einzige verfügbare aktive Indexer. In Zukunft können sich mehr Indexer dem dezentralen Netzwerk von The Graph anschließen. Diese neuen Indexer können auswählen, welche Untergraphen indiziert werden sollen. Wenn Ihr Untergraph aufgrund von Arrays schlecht optimiert ist, wird er wahrscheinlich von keinem Indexer erfasst.

Um unsere Arrays zu optimieren, können wir die @derivedFrom Anmerkung. Mit dieser Methode kann jedes in einem Entitätstyp definierte Array-Feld automatisch von allen Entitäten des angegebenen Typs ausgefüllt werden, die mit der von uns definierten Entität verknüpft sind. Das folgende Beispiel zeigt die Verwendung der Annotation @derivedFrom.

type User @entity {
id: ID! positions: [Position!]! @derivedFrom(field: “user”)
}type Position @entity {
id: ID! user: User! # This is the ID String of the User
}

Im obigen Beispiel haben wir einen Benutzer mit einer automatisch generierten Liste der Position -Entitäten. Immer wenn unser Untergraph eine Abfrage erhält, in der nach dem Positionsfeld der Entität User gefragt wird, führt der Untergraph eine umgekehrte Suche für alle Entitäten vom Typ Position durch verknüpft mit der spezifischen Entität User in ihrem Feld user. Auf diese Weise sind die verknüpften Entitäten diejenigen, die die Zeichenfolgen-ID anderer Entitäten in einem ihrer Felder haben.

Mit der Annotation @derivedFrom können wir die Entität definieren Geben Sie den gewünschten Typ für unsere Array-Daten ein, definieren Sie das Feld, das beim Ableiten des Arrays verwendet wird, und verknüpfen Sie es über deren ID mit der ursprünglichen Entität. Es gibt auch den Vorteil, dass den Entitäten, die die Array-Daten darstellen, mehr Daten hinzugefügt werden können (z. B. Metadaten erstellen oder aktualisieren). Da es sich um vollwertige Entitäten handelt, können wir sie einfach aktualisieren, indem wir ihre IDs laden, anstatt sie im Array nachzuschlagen.

Beim Behandeln von Arrays mit der Annotation @derivedFrom ist einfacher, es gibt noch einige Überlegungen zu beachten.Erstens funktioniert es nur mit Eins-zu-Viele-Beziehungen. In vielen-zu-vielen-Beziehungen benötigen wir immer noch eine Seite der Gleichung, um das Array manuell zu behandeln. Zweitens können Sie nicht auf die Array-Daten zugreifen, während der Untergraph indiziert wird, da das Array bei der Abfrage ausgefüllt wird.

Erstellen einer Benennung Konvention für Entitäts-IDs

Alle in der Datei schema.graphql definierten Entitäten werden durch ein ID-Feld identifiziert deklariert als ID! -Typ, der als Zeichenfolge dargestellt wird. Das ID-Feld ist wichtig, da es zum Laden, Erstellen und Speichern von Entitäten verwendet wird.

Da das ID-Feld das primäre Mittel zum Identifizieren einer Entität ist, sollte es immer eindeutig sein. Es ist jedoch nicht schwierig, die Eindeutigkeit eines Ausweises zu gewährleisten. Während der Indexzeit vorhandene Daten können kombiniert werden, um eindeutige IDs zu generieren. Der folgende Code ist ein Beispiel dafür.

event.transaction.hash.toHex() + "-" + 
event.logIndex.toString()

Indem Sie den Transaktions-Hash eines Ereignisses (eindeutig für verschiedene Transaktionen) nehmen und an den Protokollindex für anhängen Für das jeweilige Ereignis (das ein Ereignis innerhalb einer Transaktion identifiziert) können wir eine eindeutige zusammengesetzte ID generieren. Auf diese Weise können wir eine bestimmte Entität unter anderen Entitäten desselben Typs identifizieren, vorausgesetzt, für ein einzelnes Ereignis wird nur eine einzige Entität erstellt. Bei Bedarf können wir auch weitere Daten anhängen, um eine beliebige Anzahl von Entitäten, die im selben Ereignis erstellt wurden, eindeutig zu identifizieren. Beispielsweise könnten wir für jedes Mal, wenn eine Entität erstellt wird, einen Zähler festlegen und den Wert an die neu erstellte Entität anhängen.

Eine einfache Methode zum Generieren eindeutiger IDs für unsere Entitäten ist zwar praktisch, wir sollten dies jedoch auch tun bemühen sich, IDs zu generieren, die vorhersehbar sind und auf die verwiesen werden kann. Wenn wir Entitäten haben, die sich auf einen Teil unserer Domain beziehen, der wahrscheinlich von Endbenutzern über ihre ID abgefragt wird, können wir eine ID generieren, die auf die Domain verweist, an der wir arbeiten.

Betrachten Sie als Beispiel Ein Szenario, in dem wir eine Account -Entität in einem DEX-Untergraphen erstellen. Diese Account -Entität speichert das Guthaben des Benutzers sowie andere Informationen. Wenn wir die Entitäts-ID basierend auf dem Transaktions-Hash erstellen, kann der Benutzer nach der Transaktion suchen, die sie zuerst erstellt hat, und sie neu erstellen. Dies ist jedoch nicht intuitiv. Eine bessere Alternative wäre, eine ID basierend auf der Ethereum-Adresse des Benutzers zu erstellen und diese bei Bedarf mit etwas anderem zu kombinieren, das für die Domain relevant ist. Auf diese Weise können wir ein bestimmtes Benutzerkonto anhand anderer Konten desselben Benutzers eindeutig identifizieren.

Zusammenfassend können generische eindeutige IDs ohne domänenspezifische Daten für Entitäten nützlich sein, die nicht ständig aktualisiert werden. Dies ist ideal für Entitäten, die zum Speichern von Metadaten für domänenspezifische Ereignisse erstellt wurden, die von einem abgeleiteten Array auf einer Hauptentität verwendet werden. Generische eindeutige IDs eignen sich beispielsweise besser für Übertragungen, Mints, Burns und Swaps.

Andererseits sind domänenspezifische IDs ideal für Hauptentitäten und alle anderen Entitäten, die häufig aktualisiert werden. Sie verwenden wahrscheinlich eine Kombination aus einer Ethereum-Adresse und einigen anderen domänenspezifischen IDs. In den meisten Fällen generiert ein intelligenter Vertrag eindeutige IDs und protokolliert diese bei den Ereignissen. Ist dies nicht der Fall, müssen Sie den Smart-Vertrag untersuchen und herausfinden, was Ihre Entität einzigartig macht, und diese Daten zum Generieren einer ID verwenden.

Als Randnotiz die und toHexString(), die häufig zum Generieren von IDs aus Adressen oder Hashes verwendet werden, geben eine Zeichenfolge in Kleinbuchstaben zurück. Wenn Sie also einen Untergraphen nach Entitäten abfragen, sollte die angegebene ID-Zeichenfolge in Kleinbuchstaben geschrieben werden, da bei der Abfrage zwischen Groß- und Kleinschreibung unterschieden wird.

Weitere Informationen zur Entwicklung von Untergraphen finden Sie unter offizielle Dokumentation . Weitere Details finden Sie auch im GitHub-Repository des Projekts. The Graph hat auch eine aktive und wachsende Community, die bereit ist, zu helfen und die auftretenden Fragen zu beantworten. Wir empfehlen allen, die daran interessiert sind, ihre eigenen Untergraphen zu entwickeln, sich dem Discord-Server von Graph anzuschließen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.