When does a boat have data?

A common starting question for any analysis is "what time windows is there data for this boat?". Njord exposes this at three levels of granularity, and the right one depends on the question being asked. This page covers all three, with GraphQL examples for each.

The three levels:

  • Event-level — calendar periods marked as a regatta, training camp, or season block. Good for "what events did this boat participate in?".
  • Race-level — individual races with precise gun and finish times. Good for "the third race of Sunday".
  • Segment-level — the raw upload reality. Each LogDataSegment is one chunk of uploaded log data (typically one sailing day from one device). Good for "all data we have for this boat", including deliveries, practice days, or anything not wrapped in an event.

Event-level

For events a boat participated in within a specific date range — typically the right starting point because you usually have at least a rough sense of "when":

query EventsForBoat($boatKey: ID!, $from: Date!, $to: Date!) {
  boat(key: $boatKey) {
    eventsBetween(startTime: $from, endTime: $to) {
      key
      name
      startTime
      endTime
      timezone
    }
  }
}

Pass an explicit startTime / endTime. boat.events exists but is unbounded — on busy accounts it can return many hundreds of entries — so prefer eventsBetween with a range that matches the question, even if that range is wide (e.g. the current season).

For the most recently started (or about to start) event the user has access to:

query LatestEvent {
  latestEvent { key name startTime endTime timezone }
}

For a specific calendar day — handles the event's own timezone for you, which eventsBetween does not:

query EventsOnDate($date: String!) {
  eventsOnDate(date: $date) { key name timezone }
}

Date format is YYYY-MM-DD.

For events matching a name (e.g. a regatta the user named) regardless of date:

query FindEventByName($name: String!) {
  listEvents(filter: { nameMatches: $name }) {
    cursor
    event { key name startTime endTime timezone }
  }
}

listEvents is paginated and supports name + role filters but does NOT filter by time — use boat.eventsBetween or eventsOnDate for date-based queries.

Race-level

Once you have an event, drill into its races:

query RacesForEvent($eventKey: ID!) {
  event(key: $eventKey) {
    timezone
    races {
      key
      name
      startTime
      endTime
      raceType
    }
  }
}

A race's startTime is the gun time and endTime is the finish (extended slightly so the final leg is fully covered). This is the canonical reference for "during race 3 of the regatta" — the boundaries match what you see in the Analytics race sidebar.

Races optionally have a defined course (start line + marks + finish). Without a course, only the time window is reliable; per-leg fields elsewhere in the API require a complete course definition. Use the list-races-with-course example to filter to races that have one.

Segment-level

A LogDataSegment is one chunk of uploaded log data and exists regardless of whether the user has organised the data into events. Useful when you want everything Njord has for a boat — deliveries, practice days, race weeks, the lot.

For segments in a date range you have in mind:

query SegmentsForBoatBetween($boatKey: ID!, $from: Date!, $to: Date!) {
  boat(key: $boatKey) {
    logDataSegmentsBetween(startTime: $from, endTime: $to) {
      key
      startTime
      endTime
      timezone
      metrics
      records
    }
  }
}

For "recent N segments" without a specific date in mind, paginate from the newest:

query RecentSegments($boatKey: ID!, $limit: Int!) {
  boat(key: $boatKey) {
    listLogDataSegments(limit: $limit, reverse: true) {
      cursor
      logDataSegment {
        key
        startTime
        endTime
        timezone
        metrics
        records
      }
    }
  }
}

reverse: true returns newest first (also the default). Prefer listLogDataSegments or logDataSegmentsBetween over the unbounded boat.logDataSegments, which can return very large lists on active boats.

Other useful variants on Boat:

  • boat.logDataSegmentsInRace(raceKey) — segments that overlap a specific race

Or starting from a date instead of a boat:

query SegmentsOnDate($date: String!) {
  logDataSegmentsOnDate(date: $date) {
    key
    startTime
    endTime
    timezone
  }
}

Choosing the right level

  • "What regattas did we sail this year?" → event-level
  • "The third race of Sunday" or any specific race → race-level (after locating the event)
  • "All data we have for this boat", "that delivery passage", or anything outside event structure → segment-level

For analytical work the typical path is two or three hops: boat → events → races → drill into one race. From a race's startTime and endTime you have a precise window to pull instrument data for. For exploratory questions where you're not sure what's there, start at segment-level and work upward.

Notes

  • All times in the API are stored as ISO 8601 UTC. Events and races carry a timezone (IANA name like Europe/Stockholm). Convert to local time before showing to users — a race in Palma at 11:42 local should not appear as 09:42Z.
  • boat.events returns events the boat is associated with; a boat can be added to or removed from events without affecting the underlying data.
  • Segment boundaries are usually one sailing day; continuous multi-day offshore recordings can be longer.