Mine sisu juurde
Sursa Developers

Eksport andmelattu

Analüütikud soovivad sageli hoida Sursa andmeid ettevõtte ülejäänud andmete kõrval: millised kaardid on kontrollitud ja kes need kontrollis, kuidas teadmised meeskondade kaupa kasvavad, millised küsimused jäävad vastuseta. See juhend loob ajastatud töö, mis kopeerib Sursa andmed teie andmelattu ja hoiab koopia ajakohasena.

Töö ühendab kolm API osa:

OsaAnnab teile
Kaartide loend parameetriga updated_since ja tervikuna loetavad lühikesed loendidPärast viimast käivitust muutunud objektide praeguse oleku.
Sündmuste lintKustutamised ja toimunu ajaloo 30 päeva kohta.
KursoridTäielikud lehed ilma lünkade ja kordusteta.

Vajate võtit ulatustega cards:read ja users:read ning sündmuste lindi jaoks ulatust webhooks:manage. Andke tööle oma võti rolliga admin: kasutajate täielik loend ja sündmuste lint on avatud ainult sellele. Kitsama rolli ja andmeprofiiliga võti ekspordib ainult seda, mida teatud rühm näha tohib; see loeb kasutajate lühiloendit (brief=true) ega loe sündmuste linti, seega saab see kustutamised allpool kirjeldatud iganädalasest täielikust laadimisest.

Tabelid

Lihtne ülesehitus, kus on üks tabel iga objekti jaoks ja üks tabel sündmuste jaoks:

TabelVõtiTäidetakse päringuga
sursa_cardsidGET /v1/cards
sursa_collectionsidGET /v1/collections
sursa_usersidGET /v1/users
sursa_groupsidGET /v1/groups
sursa_eventsidGET /v1/webhook-events

Salvestage iga objekt saabunud kujul JSON-veeruna ning lisaks veerud, mille järgi sageli päringuid teete (updated_at, collection_id, status, owner_id). API hilisemates versioonides lisandub uusi välju; JSON-veeruga saate need kätte tööd muutmata.

Esmane laadimine

Lugege iga loend täielikult, ilma parameetrita updated_since, ja kirjutage iga objekt. Jätke meelde hetk, mil laadimine algas: järgmine käivitus jätkab sealt.

Inkrementaalsed laadimised

Igal käivitusel, näiteks iga 15 minuti järel:

  1. Jätke meelde selle käivituse algusaeg.
  2. Lugege kaarte parameetriga updated_since, mille väärtus on eelmise käivituse algusaeg miinus minut varu, ja küsige iga järgmist lehte kursoriga ja sama parameetriga updated_since (kursor ilma esimese lehe filtriteta tagastab 400 api.cursor_invalid). Lugege kogud, kasutajad ja rühmad tervikuna: kogudel ja kasutajatel ei ole välja updated_at ning rühma updated_at ei muutu, kui muutuvad selle liikmed. Looge või asendage iga objekt välja id järgi.
  3. Lugege sündmuste linti eelmisel korral salvestatud kursorist alates. Lisage iga sündmus tabelisse sursa_events ja rakendage kustutamised: sündmus card.deleted eemaldab kaardi tabelist sursa_cards või märgib selle kustutatuks, kui säilitate ajalugu.
  4. Salvestage algusaeg ja lindi uus kursor andmetega samas tehingus, kui teie andmeladu seda toetab.
import json
from datetime import datetime, timedelta, timezone

LISTS = {"cards": "/v1/cards", "collections": "/v1/collections", "users": "/v1/users", "groups": "/v1/groups"}


def read_list(path, since):
    """Every object of a list, changed since `since` (or all of them). The next page keeps the filters of the first."""
    params = {"limit": 200}
    if since:
        params["updated_since"] = (since - timedelta(minutes=1)).isoformat()
    while params:
        response = session.get(BASE + path, params=params, timeout=120)
        response.raise_for_status()
        body = response.json()
        items = body["data"] if isinstance(body, dict) and "data" in body else body
        yield from items
        if isinstance(body, dict) and "data" in body:
            params = {**params, "cursor": body["next_cursor"]} if body.get("has_more") else None
        else:
            cursor = response.headers.get("X-Next-Cursor")
            params = {**params, "cursor": cursor} if cursor else None


def read_events(cursor):
    """New events of the feed after `cursor` (or from the start of the 30 days), and the cursor to save."""
    events = []
    params = {"limit": 200, **({"cursor": cursor} if cursor else {})}
    while True:
        page = api("GET", "/v1/webhook-events?" + requests.compat.urlencode(params))
        events += page["data"]
        params["cursor"] = page["next_cursor"]
        if not page["has_more"]:
            return events, page["next_cursor"]


def run(state, warehouse):
    started_at = datetime.now(timezone.utc)
    since = state.get("since")
    for table, path in LISTS.items():
        for obj in read_list(path, since if table == "cards" else None):
            warehouse.upsert(f"sursa_{table}", obj["id"], json.dumps(obj))

    events, feed_cursor = read_events(state.get("feed_cursor"))
    for event in events:
        warehouse.insert_once("sursa_events", event["id"], json.dumps(event))
        if event["type"] == "card.deleted":
            warehouse.delete("sursa_cards", event["object"]["id"])

    warehouse.save_state({"since": started_at, "feed_cursor": feed_cursor})

Lindi kursor tagastatakse igal lehel, ka viimasel. Kui see salvestada, algab järgmine käivitus täpselt pärast viimast salvestatud sündmust, nii et ühtegi sündmust ei loeta kaks korda ega jäeta vahele.

Koopia täpsuse hoidmine

  • Üle 30 päeva ilma käivituseta. Lint säilitab sündmusi 30 päeva. Kui töö ei ole kauem käivitunud, tehke uuesti täielik laadimine ja eemaldage oma tabelitest kõik objektid, mida täielik laadimine ei tagastanud.
  • Iganädalane täielik laadimine. Isegi korras lindi puhul on kord nädalas tehtud ja teie tabelitega võrreldud täielik laadimine odav viis veenduda, et koopia on täielik.
  • Mida võti ei näe, seda ei ekspordita. Töö näeb täpselt seda, mida selle võti näeb. Kui kaart jääb võtme juurdepääsust välja, näiteks seetõttu, et see teisaldati piiratud kogusse, ei tagasta täielik laadimine seda; käsitlege seda eemaldatuna.
  • Küsimused. Küsimuste logil on oma eksport: GET /v1/questions/export.csv tagastab perioodi küsimused ühe CSV-failina koos hinnangute ja allikatega. Selleks on vaja ulatust ask.

Piirangute järgimine

Suure organisatsiooni täielik laadimine teeb palju päringuid. Lugege üht loendit korraga väärtusega limit=200 ja jälgige päiseid RateLimit. Iga 15 minuti järel käivituv töö, mis loeb ainult muudatusi, jääb igast kvoodist kaugele alla.