Subgraph Development, Del 2: Hantering av arrays och identifiering av enheter

(ProtoFire.io)

(Del 1 ) | Del 2

Detta blogginlägg ger praktiska rekommendationer om hur du använder arrays effektivt och genererar enhets-ID: n som är unika och referera.

I del 1 av denna serie gav vi en översikt över underbilder för att hjälpa utvecklare att förstå deras grundläggande struktur. Dessutom delade vi också våra insikter för kartläggning och aggregering av data.

Den här gången kommer vi att diskutera ytterligare två ämnen: hantering av matriser och generering av ID för enheter som både är unika och som enkelt refereras till. Som en del av diskussionen kommer vi att ge våra rekommendationer om hur man effektivt hanterar arrayer och korrekt namn på enheter.

Hanterar arrays effektivt

Att lägga till matriser till enheter är användbart i vissa scenarier. Det finns till exempel fall där vi behöver modellera en lista med adresser för en datakälla eller spåra historiska förändringar för ett visst fält över tiden.

Utan förkunskap om hur matriser fungerar inom underbilder kan vi överväga skapa ett fält av en arraytyp i en enhetstypsdefinition (inom schema.graphql -filen) och initialisera en tom array när en ny enhet av samma typ skapas. När ny data läggs till i matrisen kan vi skicka data och spara enheten. Även om detta låter intuitivt fungerar det tyvärr inte.

Manuell hantering av matriser på underbilder, särskilt i scenariot ovan, har några försiktighetsåtgärder. När du öppnar en matris av en enhet är det du får en kopia av matrisen. Således, om du lägger till ny data och sparar enheten, fungerar det inte som du förväntar dig, eftersom du helt enkelt ändrar en kopia av matrisen, medan originalet är oförändrat.

För att uppdatera den faktiska matrisen kan vi placera kopian av matrisen i en variabel och sedan ändra data. Därefter kan vi ställa in variabeln som den nya matrisen på enheten. På detta sätt ersätts den gamla matrisen med kopian. Denna process för att uppdatera arrayen exemplifieras i följande kod.

// 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()

Även om du kan uppdatera en array på det sätt som visas ovan är det inte en idealisk lösning . Förutom att det är obekvämt finns det en annan anledning att inte hantera matriser manuellt – tidsresor. (Läs del 1 av serien för att lära dig mer om tidsresor.)

Det är bara möjligt att utföra tidsresor, eftersom underbilder håller reda på alla förändringar i alla enheter som presenterar alla tid. Om det finns många enheter med matrisfält, som är stora och uppdateras ofta, måste också kopior av alla matriser lagras. Detta kommer att ta en avgift på prestanda och diskutrymme för alla indexerare som indexerar din underbild.

För närvarande är Graphs värdtjänst den enda aktiva indexeraren som finns tillgänglig. I framtiden kan fler indexerare gå med tillägget av The Graphs decentraliserade nätverk. Dessa nya indexerare kommer att kunna välja vilka underbilder som ska indexeras. Om ditt underbild är dåligt optimerat på grund av matriser kommer det troligtvis inte att plockas upp av någon indexerare.

För att optimera våra matriser kan vi använda @derivedFrom anteckning. Med den här metoden kan alla matrisfält som definierats i en enhetstyp automatiskt fyllas av alla enheter av den angivna typen som är länkade till den enhet som vi definierar. Följande exempel visar användningen av @derivedFrom -anteckningen.

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
}

I exemplet ovan har vi en användare med en automatiskt genererad lista över Position -enheterna. Närhelst vår underbild tar emot en fråga som frågar efter positionsfältet för User -enheten, utför underbilden en omvänd uppslagning för alla enheterna Position länkad till det specifika User -enheten i deras user -fält. På detta sätt är de länkade enheterna de som har sträng-ID för andra enheter i ett av dess fält.

Med hjälp av @derivedFrom -anteckningen kan vi definiera enheten typ som vi vill ha för vår array-data, definiera fältet som används vid härledning av arrayen och länka det till den ursprungliga enheten via deras ID. Det finns också fördelen med att kunna lägga till mer data (t.ex. skapa eller uppdatera metadata) till enheterna som representerar arraydata. Eftersom dessa är fullfjädrade enheter kan vi enkelt uppdatera dem genom att ladda deras ID istället för att leta upp dem i matrisen.

När vi hanterar arrayer med @derivedFrom -anteckningen är lättare, det finns fortfarande några överväganden att vara medvetna om.För det första fungerar det bara med en-till-många-relationer. I många-till-många-relationer behöver vi fortfarande en sida av ekvationen för att manuellt hantera arrayen. För det andra kommer du inte att kunna komma åt arraydata medan subgrafen indexeras, eftersom arrayen fylls i efterfrågan.

Skapa en namngivning konvention för entitets-ID

Alla enheter definierade i schema.graphql -filen identifieras av ett ID-fält som är deklareras som en ID! typ representerad som en sträng. ID-fältet är viktigt eftersom det används för att ladda, skapa och spara enheter.

Eftersom ID-fältet är det primära sättet att identifiera en enhet bör det alltid vara unikt. Som sagt är det inte svårt att garantera det unika med ett ID. Data som finns under indextiden kan kombineras för att skapa unika ID: n. Följande kod är ett exempel på detta.

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

Genom att ta transaktionshash för en händelse (unik för olika transaktioner) och lägga till den i loggindex för den specifika händelsen (som identifierar en händelse inom en transaktion) kan vi skapa ett unikt sammansatt ID. På så sätt kan vi identifiera en viss enhet bland andra enheter av samma typ förutsatt att endast en enda enhet skapas för en enda händelse. Om det behövs kan vi också lägga till mer data för att identifiera valfritt antal enheter som skapats i samma händelse. Vi kan till exempel ställa in en räknare för varje gång en enhet skapas och lägga till värdet till den nyskapade enheten.

Även om det är praktiskt att ha en enkel metod för att skapa unika ID för våra enheter, bör vi också sträva efter att generera ID som är förutsägbara och kan refereras till. Om vi ​​har enheter relaterade till en del av vår domän som sannolikt kommer att bli förfrågade av slutanvändare via deras ID kan vi skapa ett ID som refererar till den domän vi arbetar med.

Som ett exempel, överväg ett scenario där vi skapar en Account -enhet i en DEX-underbild. Denna Account -enhet lagrar användarens saldo och annan information. Om vi ​​skapar enhets-ID baserat på transaktionshash kan användaren först söka efter transaktionen som skapade den och återskapa den, men den kommer inte att vara intuitiv. Ett bättre alternativ skulle vara att skapa ett ID baserat på användarens Ethereum-adress och vid behov kombinera det med något annat som är relevant för domänen. På så sätt kan vi unikt identifiera ett visst användarkonto från andra konton för samma användare.

Sammanfattningsvis kan generiska unika ID: n utan domänspecifika data vara användbara för enheter som inte kommer att uppdateras kontinuerligt. Detta är perfekt för enheter som skapats för att spara metadata för domänspecifika händelser som kommer att konsumeras från en härledd matris på en huvudenhet. Generiska unika ID: n är till exempel bättre lämpade för överföringar, myntverk, brännskador och byten.

Å andra sidan är domänspecifika ID: n idealiska för huvudenheter och andra enheter som kommer att få frekventa uppdateringar. Det är troligt att du använder en kombination av en Ethereum-adress och några andra domänspecifika ID: n. I de flesta fall genererar ett smart kontrakt unika ID och loggar dem på händelserna. Om detta inte är fallet måste du studera det smarta kontraktet och identifiera vad som gör din enhet unik och använda den informationen för att generera ett ID.

Som en sidnot, toHex() och toHexString() -metoder – som vanligtvis används för att generera ID: n från adresser eller haschar – returnerar en gemenersträng. Detta innebär att när du frågar efter en undergraf för enheter ska den angivna ID-strängen vara gemener eftersom frågan är skiftlägeskänslig.

För mer information om utveckling av subgraf, se grafens officiell dokumentation . Ytterligare detaljer finns också i projektets GitHub-arkiv . Diagrammet har också ett aktivt och växande samhälle som är redo att hjälpa och svara på de uppkomna frågorna. Vi uppmuntrar alla som är intresserade av att utveckla sina egna underbilder att gå med i Graphs Discord-server .

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *