<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matthias</title>
    <description>The latest articles on DEV Community by Matthias (@mcb77).</description>
    <link>https://dev.to/mcb77</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2629294%2F9d0db39d-5968-4b9b-8088-5e2b3b35f6a8.jpg</url>
      <title>DEV Community: Matthias</title>
      <link>https://dev.to/mcb77</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mcb77"/>
    <language>en</language>
    <item>
      <title>Basics of Animal Tracking Databases: Crafting the Schema</title>
      <dc:creator>Matthias</dc:creator>
      <pubDate>Sun, 06 Apr 2025 16:00:33 +0000</pubDate>
      <link>https://dev.to/mcb77/basics-of-animal-tracking-databases-crafting-the-schema-278i</link>
      <guid>https://dev.to/mcb77/basics-of-animal-tracking-databases-crafting-the-schema-278i</guid>
      <description>&lt;p&gt;&lt;strong&gt;“ChatGPT, whip up a next-gen animal tracking database for me…”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpafwxetnybimna0co2t4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpafwxetnybimna0co2t4.png" alt="Image description" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
In my last post, &lt;a href="https://dev.to/mcb77/basics-of-animal-tracking-databases-2b4e"&gt;&lt;em&gt;Basics of Animal Tracking Databases&lt;/em&gt;&lt;/a&gt;, we nailed the essentials: core entities, a tight data model, and why SQL is the MVP for most tracking gigs. Now, let’s get our hands dirty and actually build a PostgreSQL schema. Who doesn’t love a good, structured database?&lt;/p&gt;


&lt;h2&gt;
  
  
  Why PostgreSQL?
&lt;/h2&gt;

&lt;p&gt;PostgreSQL is the Swiss Army knife of SQL databases. It’s got structured data, rock-solid relationships, and ACID compliance, plus it’s free and open-source. For our median Movebank study (10 tags, 10,000 locations), it’s a perfect fit.&lt;/p&gt;

&lt;p&gt;We’ll use it to bring five key entities to life: &lt;strong&gt;Study&lt;/strong&gt;, &lt;strong&gt;Tag&lt;/strong&gt;, &lt;strong&gt;Animal&lt;/strong&gt;, &lt;strong&gt;Deployment&lt;/strong&gt;, and &lt;strong&gt;Location&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s build this thing.&lt;/p&gt;


&lt;h2&gt;
  
  
  Setting the Stage
&lt;/h2&gt;

&lt;p&gt;First, we need a fresh sandbox. Fire up your PostgreSQL tool of choice (&lt;code&gt;psql&lt;/code&gt;, &lt;code&gt;pgAdmin&lt;/code&gt;, whatever vibes with you) and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Create the database to house our tracking data&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;animal_tracking&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Connect to it&lt;/span&gt;
&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="n"&gt;animal_tracking&lt;/span&gt;

&lt;span class="c1"&gt;-- Set up a schema for organization&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;SCHEMA&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boom. A clean database and a tracking schema to keep our tables organized. Simple but effective.&lt;/p&gt;




&lt;h2&gt;
  
  
  Crafting the Schema
&lt;/h2&gt;

&lt;p&gt;Here’s the fun part: turning our data model into tables. Five entities, each with fields, keys, and relationships, ready to handle real tracking data. Let’s roll.&lt;/p&gt;

&lt;p&gt;Let's revisit the Entity-Relationship diagram from the previous post:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjiw6dnj08tst3avi6ujv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjiw6dnj08tst3avi6ujv.png" alt="Image description" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Study
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;study&lt;/code&gt; table is our anchor. Everything ties back to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Table for research studies, the top-level entity&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;study&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;study_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- Unique ID for each study&lt;/span&gt;
    &lt;span class="n"&gt;study_name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;       &lt;span class="c1"&gt;-- Human-readable study name&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;study_id&lt;/code&gt; is our unique identifier. &lt;code&gt;study_name&lt;/code&gt; gives it a readable label. Easy peasy.&lt;/p&gt;




&lt;h3&gt;
  
  
  Tag
&lt;/h3&gt;

&lt;p&gt;Next up, &lt;code&gt;tag&lt;/code&gt;. This is the hardware pumping out data, linked to a study.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Table for tracking devices&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;tag_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                 &lt;span class="c1"&gt;-- Unique ID for each tag&lt;/span&gt;
    &lt;span class="n"&gt;study_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;study&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;study_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;-- Link to parent study&lt;/span&gt;
    &lt;span class="n"&gt;tag_manufacturer&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                      &lt;span class="c1"&gt;-- Optional: who made the tag&lt;/span&gt;
    &lt;span class="n"&gt;tag_model&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;                              &lt;span class="c1"&gt;-- Optional: tag model details&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;study_id&lt;/code&gt; hooks each tag to its study with a foreign key. Manufacturer and model are optional for flexibility.&lt;/p&gt;




&lt;h3&gt;
  
  
  Animal
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;animal&lt;/code&gt; table is for our stars: wolves, eagles, you name it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Table for tracked animals&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;animal_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;-- Unique ID for each animal&lt;/span&gt;
    &lt;span class="n"&gt;study_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;study&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;study_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;-- Link to parent study&lt;/span&gt;
    &lt;span class="n"&gt;animal_name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                           &lt;span class="c1"&gt;-- Optional: name or identifier&lt;/span&gt;
    &lt;span class="n"&gt;animal_sex&lt;/span&gt; &lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;                         &lt;span class="c1"&gt;-- M/F/U for male, female, unknown&lt;/span&gt;
    &lt;span class="n"&gt;animal_species&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;                         &lt;span class="c1"&gt;-- Species name&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another &lt;code&gt;study_id&lt;/code&gt; foreign key keeps animals tied to their study. &lt;code&gt;animal_sex&lt;/code&gt; is M/F/U (unknown). Short and sweet.&lt;/p&gt;




&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;deployment&lt;/code&gt; table is the glue, linking tags to animals over time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Table to track when tags are attached to animals&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deployment&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;deployment_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                     &lt;span class="c1"&gt;-- Unique ID for each deployment&lt;/span&gt;
    &lt;span class="n"&gt;study_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;study&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;study_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;-- Link to study&lt;/span&gt;
    &lt;span class="n"&gt;tag_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;       &lt;span class="c1"&gt;-- Link to tag&lt;/span&gt;
    &lt;span class="n"&gt;animal_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animal_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;-- Link to animal&lt;/span&gt;
    &lt;span class="n"&gt;deployment_start_timestamp&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;-- When tag was attached&lt;/span&gt;
    &lt;span class="n"&gt;deployment_end_timestamp&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt;                    &lt;span class="c1"&gt;-- When tag was removed (nullable if active)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three foreign keys and timestamps track when a tag’s on duty. &lt;code&gt;deployment_end_timestamp&lt;/code&gt; stays nullable for active deployments.&lt;/p&gt;




&lt;h3&gt;
  
  
  Location
&lt;/h3&gt;

&lt;p&gt;Finally, &lt;code&gt;location&lt;/code&gt;. This is where the magic happens: GPS points from tags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Table for GPS location data generated by tags&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;tag_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;-- Link to tag generating data&lt;/span&gt;
    &lt;span class="n"&gt;location_longitude&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                 &lt;span class="c1"&gt;-- Longitude&lt;/span&gt;
    &lt;span class="n"&gt;location_latitude&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                  &lt;span class="c1"&gt;-- Latitude&lt;/span&gt;
    &lt;span class="n"&gt;location_timestamp&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;       &lt;span class="c1"&gt;-- When the point was recorded&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;tag_id&lt;/code&gt; ties each point to its device. This design assumes GPS data is tied to &lt;strong&gt;tags&lt;/strong&gt;, not animals directly. Use the &lt;code&gt;deployment&lt;/code&gt; table to find out which animal wore the tag at any point in time.&lt;/p&gt;




&lt;h3&gt;
  
  
  Double-Checking
&lt;/h3&gt;

&lt;p&gt;Run this in &lt;code&gt;psql&lt;/code&gt; to make sure everything’s there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- List all tables in the tracking schema&lt;/span&gt;
&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see: &lt;code&gt;study&lt;/code&gt;, &lt;code&gt;tag&lt;/code&gt;, &lt;code&gt;animal&lt;/code&gt;, &lt;code&gt;deployment&lt;/code&gt;, and &lt;code&gt;location&lt;/code&gt;. If they’re listed, we’re in business!&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Recap
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Table&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;study&lt;/td&gt;
&lt;td&gt;Top-level research project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tag&lt;/td&gt;
&lt;td&gt;GPS tracking hardware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;animal&lt;/td&gt;
&lt;td&gt;The tracked individual (e.g., wolf)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deployment&lt;/td&gt;
&lt;td&gt;Connects tag to animal over time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;location&lt;/td&gt;
&lt;td&gt;Stores GPS coordinates from tags&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;p&gt;We’ve got a lean, mean schema. It’s relational, structured, and ready to rock.&lt;/p&gt;

&lt;p&gt;Next time, we’ll load it with some tracking data and start querying the heck out of it. Got a specific angle you’d like to explore next—spatial queries, performance tips, or real-time ingestion? Drop me a line. Let’s build it together.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br&gt;
Matthias Berger has been a key member of the Movebank Development Team since its inception in 2008, contributing to the advancement of animal tracking databases and supporting researchers worldwide.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>animaltracking</category>
      <category>gps</category>
      <category>sql</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Basics of Animal Tracking Databases</title>
      <dc:creator>Matthias</dc:creator>
      <pubDate>Sun, 19 Jan 2025 16:46:32 +0000</pubDate>
      <link>https://dev.to/mcb77/basics-of-animal-tracking-databases-2b4e</link>
      <guid>https://dev.to/mcb77/basics-of-animal-tracking-databases-2b4e</guid>
      <description>&lt;p&gt;&lt;strong&gt;“ChatGPT, Please create a Next Gen Animal Tracking Database for me…”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwin02e59b5s0wm0ie1j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwin02e59b5s0wm0ie1j.png" alt="Image description" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Designing a robust database for animal tracking can be challenging, but it doesn't have to be complicated. Let's break down the essentials in a simple and engaging way.&lt;/p&gt;

&lt;p&gt;There are a lot of opinions on what the right technology is for animal tracking databases. At the end of the day, we need something that works for the everyday user of animal tracking data. Let’s look at some facts.&lt;/p&gt;

&lt;p&gt;For example, a preliminary analysis of publicly available Movebank studies reveals that the &lt;strong&gt;median study&lt;/strong&gt; contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;10 Tags&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;10,000 Locations&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s perfectly fine for SQL. We can work with that.&lt;/p&gt;

&lt;p&gt;Don’t get me wrong—there &lt;em&gt;are&lt;/em&gt; amounts of data and especially “rates of data” in real-time monitoring tracking systems which are problematic for a pure SQL approach. But there are many more challenges than simply switching to something NoSQL-ish. Let’s keep that for the “Non-Basics of Animal Tracking Databases” article.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Immense Advantages of SQL Databases
&lt;/h3&gt;

&lt;p&gt;SQL databases shine in their ability to manage structured data efficiently. They offer powerful querying capabilities, robust transactional support, and strong data integrity through ACID compliance. With a mature ecosystem of tools and widespread adoption, SQL databases provide excellent scalability for moderate data sizes and are a trusted choice for applications requiring complex relationships, such as animal tracking systems. Their familiarity among developers also ensures faster development and maintenance cycles.&lt;/p&gt;

&lt;p&gt;In the context of animal tracking, SQL databases excel in managing structured data like study metadata, tag information, and deployment details while ensuring integrity and consistency across related entities.&lt;/p&gt;




&lt;h3&gt;
  
  
  Core Entities in an Animal Tracking Database
&lt;/h3&gt;

&lt;p&gt;Let’s have a look at the basic entities in an animal tracking database.&lt;/p&gt;

&lt;p&gt;Take a look at this simple model of Movebank, available here: &lt;a href="https://www.movebank.org/cms/movebank-content/mb-data-model" rel="noopener noreferrer"&gt;Movebank Data Model&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc4n34n8yaaoh3h51i2yq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc4n34n8yaaoh3h51i2yq.png" alt="Image description" width="778" height="643"&gt;&lt;/a&gt;&lt;br&gt;
The basic entities are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Study&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tag&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deployment&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animal&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event&lt;/strong&gt; (just location events in our case)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will only focus on location data for the moment.&lt;/p&gt;

&lt;p&gt;Refer to the simple Entity-Relationship diagram below for a visual representation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9eq559n7ik67so46zvl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9eq559n7ik67so46zvl.png" alt="Image description" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  What Do These Entities Mean?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Study:&lt;/strong&gt;&lt;br&gt;
The study is the enclosing entity. It holds Tags, Deployments, Animals, and the location data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tag:&lt;/strong&gt;&lt;br&gt;
The tag represents the physical tracking device which collects the location data. Therefore, the location data is associated with the Tag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Location:&lt;/strong&gt;&lt;br&gt;
The location entity stores GPS coordinates and is linked to a specific tag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Animal:&lt;/strong&gt;&lt;br&gt;
This represents the living animal whose location is collected by the tracking device.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment:&lt;/strong&gt;&lt;br&gt;
The deployment describes the fact that the tracking device is mounted on an animal for a defined amount of time or time range.&lt;/p&gt;

&lt;p&gt;The same tracking device can be used on different animals across different time ranges. However, under normal physical conditions, a tracking device could only be mounted to exactly one animal at a point in time.&lt;/p&gt;




&lt;h3&gt;
  
  
  What’s Missing?
&lt;/h3&gt;

&lt;p&gt;Well, everything else. While these are the fundamental entities, there are plenty of other things to consider when building a fully-fledged tracking database, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Users&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Access Rights&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Imports&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Formats&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensor Types&lt;/strong&gt; (for everything besides basic location data)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visualization&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We might dive into these very interesting parts of an animal tracking database later.&lt;/p&gt;




&lt;h3&gt;
  
  
  Refined Data Model
&lt;/h3&gt;

&lt;p&gt;For now, let’s refine the data model and introduce some fields and key data types to make everything more relatable.&lt;/p&gt;

&lt;p&gt;Here are the key fields for the &lt;strong&gt;Study&lt;/strong&gt; entity:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Field&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;study_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ID&lt;/td&gt;
&lt;td&gt;Unique identifier for the study.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;study_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Name of the study.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Tag
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Field&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tag_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ID&lt;/td&gt;
&lt;td&gt;Unique identifier for the tag.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;study_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Foreign Key&lt;/td&gt;
&lt;td&gt;Links the tag to its associated study.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tag_manufacturer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Manufacturer of the tracking device.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tag_model&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Model of the tracking device.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Location
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Field&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tag_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Foreign Key&lt;/td&gt;
&lt;td&gt;Links the location data to its associated tag.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;location_longitude&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number&lt;/td&gt;
&lt;td&gt;Longitude coordinate of the location.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;location_latitude&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number&lt;/td&gt;
&lt;td&gt;Latitude coordinate of the location.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;location_timestamp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Timestamp&lt;/td&gt;
&lt;td&gt;Timestamp when the location was recorded.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Animal
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Field&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;animal_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ID&lt;/td&gt;
&lt;td&gt;Unique identifier for the animal.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;study_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Foreign Key&lt;/td&gt;
&lt;td&gt;Links the animal to its associated study.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;animal_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Name of the animal.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;animal_sex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Sex of the animal.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;animal_species&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Species of the animal.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Deployment
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Field&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deployment_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ID&lt;/td&gt;
&lt;td&gt;Unique identifier for the deployment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;study_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Foreign Key&lt;/td&gt;
&lt;td&gt;Links the deployment to its associated study.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tag_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Foreign Key&lt;/td&gt;
&lt;td&gt;Links the deployment to its associated tag.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;animal_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Foreign Key&lt;/td&gt;
&lt;td&gt;Links the deployment to its associated animal.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deployment_start_timestamp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Timestamp&lt;/td&gt;
&lt;td&gt;Start time of the deployment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deployment_end_timestamp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Timestamp&lt;/td&gt;
&lt;td&gt;End time of the deployment.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;How does the refined Entity-Relationship diagram look?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjiw6dnj08tst3avi6ujv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjiw6dnj08tst3avi6ujv.png" alt="Image description" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s looking good!&lt;/p&gt;




&lt;h3&gt;
  
  
  What’s Next?
&lt;/h3&gt;

&lt;p&gt; In the next post, we’ll explore what this looks like in &lt;strong&gt;PostgreSQL&lt;/strong&gt;, our database of choice for things like this.&lt;/p&gt;

&lt;p&gt;If there are specific things you’re interested in, just ask!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br&gt;
Matthias Berger has been a key member of the Movebank Development Team since its inception in 2008, contributing to the advancement of animal tracking databases and supporting researchers worldwide.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>animaltracking</category>
      <category>gps</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
