This code quick start enables you to easily integrate your app with Timescale Cloud. Use your favorite programming language to connect to your Timescale Cloud service, create and manage hypertables, then ingest and query data.
To follow the procedure on this page, you need to:
Create a target Timescale Cloud service
You need your connection details to follow the steps in this page. This procedure also works for self-hosted TimescaleDB.
- Install Rails.
Every Timescale Cloud service is a 100% PostgreSQL database hosted in Timescale Cloud with Timescale extensions such as TimescaleDB. You connect to your Timescale Cloud service from a standard Rails app configured for PostgreSQL.
Create a new Rails app configured for PostgreSQL
Rails creates and bundles your app, then installs the standard PostgreSQL Gems.
rails new my_app -d=postgresqlcd my_appInstall the TimescaleDB gem
Open
Gemfile
, add the following line, then save your changes:gem 'timescaledb'In Terminal, run the following command:
bundle install
Connect your app to your Timescale Cloud service
In
<my_app_home>/config/database.yml
update the configuration to read securely connect to your Timescale Cloud service by addingurl: <%= ENV['DATABASE_URL'] %>
to the default configuration:default: &defaultadapter: postgresqlencoding: unicodepool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>url: <%= ENV['DATABASE_URL'] %>Set the environment variable for
DATABASE_URL
to the value ofService URL
from your connection detailsexport DATABASE_URL="value of Service URL"Create the database:
Timescale Cloud: nothing to do. The database is part of your Timescale Cloud service.
self-hosted TimescaleDB, create the database for the project:
rails db:create
Run migrations:
rails db:migrateVerify the connection from your app to your Timescale Cloud service:
echo "\dx" | rails dbconsoleThe result shows the list of extensions in your Timescale Cloud service
Name Version Schema Description pg_buffercache 1.5 public examine the shared buffer cache pg_stat_statements 1.11 public track planning and execution statistics of all SQL statements executed plpgsql 1.0 pg_catalog PL/pgSQL procedural language postgres_fdw 1.1 public foreign-data wrapper for remote PostgreSQL servers timescaledb 2.18.1 public Enables scalable inserts and complex queries for time-series data (Community Edition) timescaledb_toolkit 1.19.0 public Library of analytical hyperfunctions, time-series pipelining, and other SQL utilities
Hypertables are PostgreSQL tables designed to simplify and accelerate data analysis. Anything you can do with regular PostgreSQL tables, you can do with hypertables - but much faster and more conveniently.
In this section, you use the helpers in the timescaledb gem to create and manage a hypertable.
Generate a migration to create the page loads table
rails generate migration create_page_loadsThis creates the
<my_app_home>/db/migrate/<migration-datetime>_create_page_loads.rb
migration file.Add hypertable options
Replace the contents of
<my_app_home>/db/migrate/<migration-datetime>_create_page_loads.rb
with the following:class CreatePageLoads < ActiveRecord::Migration[8.0]def changehypertable_options = {time_column: 'created_at',chunk_time_interval: '1 day',compress_segmentby: 'path',compress_orderby: 'created_at',compress_after: '7 days',drop_after: '30 days'}create_table :page_loads, id: false, primary_key: [:created_at, :user_agent, :path], hypertable: hypertable_options do |t|t.timestamptz :created_at, null: falset.string :user_agentt.string :patht.float :performanceendendendThe
id
column is not included in the table. This is because TimescaleDB requires that anyUNIQUE
orPRIMARY KEY
indexes on the table include all partitioning columns. In this case, this is the time column. A new Rails model includes aPRIMARY KEY
index for id by default: either remove the column or make sure that the index includes time as part of a "composite key."For more information, check the Roby docs around composite primary keys.
Create a
PageLoad
modelCreate a new file called
<my_app_home>/app/models/page_load.rb
and add the following code:class PageLoad < ApplicationRecordextend Timescaledb::ActsAsHypertableinclude Timescaledb::ContinuousAggregatesHelperacts_as_hypertable time_column: "created_at",segment_by: "path",value_column: "performance"# Basic scopes for filtering by browserscope :chrome_users, -> { where("user_agent LIKE ?", "%Chrome%") }scope :firefox_users, -> { where("user_agent LIKE ?", "%Firefox%") }scope :safari_users, -> { where("user_agent LIKE ?", "%Safari%") }# Performance analysis scopesscope :performance_stats, -> {select("stats_agg(#{value_column}) as stats_agg")}scope :slow_requests, -> { where("performance > ?", 1.0) }scope :fast_requests, -> { where("performance < ?", 0.1) }# Set up continuous aggregates for different timeframescontinuous_aggregates scopes: [:performance_stats],timeframes: [:minute, :hour, :day],refresh_policy: {minute: {start_offset: '3 minute',end_offset: '1 minute',schedule_interval: '1 minute'},hour: {start_offset: '3 hours',end_offset: '1 hour',schedule_interval: '1 minute'},day: {start_offset: '3 day',end_offset: '1 day',schedule_interval: '1 minute'}}endRun the migration
rails db:migrate
The timescaledb gem provides efficient ways to insert data into hypertables. This section shows you how to ingest test data into your hypertable.
Create a controller to handle page loads
Create a new file called
<my_app_home>/app/controllers/application_controller.rb
and add the following code:class ApplicationController < ActionController::Basearound_action :track_page_loadprivatedef track_page_loadstart_time = Time.currentyieldend_time = Time.currentPageLoad.create(path: request.path,user_agent: request.user_agent,performance: (end_time - start_time))endendGenerate some test data
Use
bin/console
to join a Rails console session and run the following code to define some random page load access data:def generate_sample_page_loads(total: 1000)time = 1.month.agopaths = %w[/ /about /contact /products /blog]browsers = ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36","Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15"]total.times.map dotime = time + rand(60).seconds{path: paths.sample,user_agent: browsers.sample,performance: rand(0.1..2.0),created_at: time,updated_at: time}endendInsert the generated data into your Timescale Cloud service
# Insert the data in batchesPageLoad.insert_all(generate_sample_page_loads, returning: false)Validate the test data in your Timescale Cloud service
PageLoad.countPageLoad.first
This section lists the most common tasks you might perform with the timescaledb gem.
The timescaledb gem provides several convenient scopes for querying your time-series data.
Built-in time-based scopes:
PageLoad.last_hour.countPageLoad.today.countPageLoad.this_week.countPageLoad.this_month.countBrowser-specific scopes:
# Count requests by browserPageLoad.chrome_users.last_hour.countPageLoad.firefox_users.last_hour.countPageLoad.safari_users.last_hour.count# Performance analysisPageLoad.slow_requests.last_hour.countPageLoad.fast_requests.last_hour.countQuery continuous aggregates:
This query fetches the average and standard deviation from the performance stats for the
/products
path over the last day.# Access aggregated performance stats through generated classesPageLoad::PerformanceStatsPerMinute.last_hourPageLoad::PerformanceStatsPerHour.last_dayPageLoad::PerformanceStatsPerDay.last_month# Get statistics for a specific pathstats = PageLoad::PerformanceStatsPerHour.last_day.where(path: '/products').select("average(stats_agg) as average, stddev(stats_agg) as stddev").firstputs "Average: #{stats.average}"puts "Standard Deviation: #{stats.stddev}"
The timescaledb gem provides utility methods to access hypertable and chunk information. Every model that uses
the acts_as_hypertable
method has access to these methods.
View chunk or hypertable information:
PageLoad.chunks.countPageLoad.hypertable.detailed_sizeCompress/Decompress chunks:
PageLoad.chunks.uncompressed.first.compress! # Compress the first uncompressed chunkPageLoad.chunks.compressed.first.decompress! # Decompress the oldest chunkPageLoad.hypertable.compression_stats # View compression stats
You collect hypertable stats using methods that provide insights into your hypertable's structure, size, and compression status:
Get basic hypertable information:
hypertable = PageLoad.hypertablehypertable.hypertable_name # The name of your hypertablehypertable.schema_name # The schema where the hypertable is locatedGet detailed size information:
hypertable.detailed_size # Get detailed size information for the hypertablehypertable.compression_stats # Get compression statisticshypertable.chunks_detailed_size # Get chunk informationhypertable.approximate_row_count # Get approximate row counthypertable.dimensions.map(&:column_name) # Get dimension informationhypertable.continuous_aggregates.map(&:view_name) # Get continuous aggregate view names
The continuous_aggregates
method generates a class for each continuous aggregate.
Get all the continuous aggregate classes:
PageLoad.descendants # Get all continuous aggregate classesManually refresh a continuous aggregate:
PageLoad.refresh_aggregatesCreate or drop a continuous aggregate:
Create or drop all the continuous aggregates in the proper order to build them hierarchically. See more about how it works in this blog post.
PageLoad.create_continuous_aggregatesPageLoad.drop_continuous_aggregates
Now that you have integrated the ruby gem into your app:
- Learn more about the timescaledb gem.
- Check out the official docs.
- Follow the LTTB, Open AI long-term storage, and candlesticks tutorials.
Keywords
Found an issue on this page?Report an issue or Edit this page in GitHub.