50
You got schema in my JSON! Evolving schemas in a schemaless world Philipp Fehre Technical Evangelist at Couchbase

You got schema in my json

Embed Size (px)

DESCRIPTION

Handling schema mirgrations and changing data in NoSQL databases. Agile Code needs Agile Data

Citation preview

Page 1: You got schema in my json

You got schema in my JSON!

Evolving schemas in a schemaless world!Philipp Fehre!Technical Evangelist at Couchbase

Page 2: You got schema in my json

From prototype to production and beyond

Page 3: You got schema in my json

–The Spec

“Create an available, scalable search index”

Page 4: You got schema in my json

Least downtime possible

Page 5: You got schema in my json

Scale horizontally

Page 6: You got schema in my json

Not the primary data source

Page 7: You got schema in my json

Welcome to NoSQL Land

Page 8: You got schema in my json

Data in —> Index Query —> IDs out

Page 9: You got schema in my json

module DB STORE = { keyOne: [1, 2], keyTwo: [1, 3, 4] } ! def self.find_all keys keys.map { |k| STORE.fetch(k.to_sym, []) } end end

Page 10: You got schema in my json

def get_search_results keys results = DB::find_all(keys) results.flatten.uniq end !get_search_results ["keyOne", “keyTwo"] ! # => [1, 2, 3, 4]

Page 11: You got schema in my json

–The Spec

“Add options for dynamic filtering.”

Page 12: You got schema in my json

Data in —> Index + Filter Data Query —> IDs out

Page 13: You got schema in my json

How to evolve the data?

Page 14: You got schema in my json

Still in the prototyping phase

Page 15: You got schema in my json

Drop and rebuild!

Page 16: You got schema in my json

module DB STORE = { keyOne: [{id: 1, prop: "bar"}, {id: 2, prop: "foo"}], keyTwo: [{id: 1, prop: "bar"}, {id: 3, prop: "bar"}, {id: 4, prop: "bar"}] } ! def self.find_all keys, prop keys.map { |k| STORE.fetch(k.to_sym, []).map { |e| e if e[:prop] == prop }.compact }

# => [[{:id=>1, :prop=>”bar"}], …] end end

Page 17: You got schema in my json

1 != {id: 1, …}

Page 18: You got schema in my json

Your code only understands one format

Page 19: You got schema in my json

Your code should only understand one format

Page 20: You got schema in my json

Implicit Schema

Page 21: You got schema in my json

def get_search_results keys, prop = "bar" results = DB::find_all(keys, prop) results.flatten.uniq.map { |e| e[:id] } end !get_search_results ["keyOne", “keyTwo"] ! # => [1, 3, 4]

Page 22: You got schema in my json

Time to go live

Page 23: You got schema in my json

Time to improve

Page 24: You got schema in my json

Part of the concept validation

Page 25: You got schema in my json

–The Spec

“Don’t hit the main datastore for preview”

Page 26: You got schema in my json

Data in —> Index + Filter Data + Cached Data Query —> JSON out

Page 27: You got schema in my json

How to evolve the data, now?

Page 28: You got schema in my json

We can’t rebuild the dataset

Page 29: You got schema in my json

In SQL this is done via migrations

Page 30: You got schema in my json

class AddFields < ActiveRecord::Migration def up change_table :quotas do |t| t.column :free, :integer end Quota.all do |qota| quota.free = calculate_free(quota) quota.save end end end

Page 31: You got schema in my json

Crawling all data is slow

Page 32: You got schema in my json

class AddFields < ActiveRecord::Migration def up change_table :quotas do |t| t.column :free, :integer end execute "COMMIT" Quota.all do |qota| quota.free = calculate_free(quota) quota.save end end end

Page 33: You got schema in my json

During Migration the implicit Schema broken

Page 34: You got schema in my json

Migrate data up “on the fly”

Page 35: You got schema in my json

Migrate data down “on the fly”

Page 36: You got schema in my json

Shorten the time until the new data is usable

Page 37: You got schema in my json

Versioning the data

Page 38: You got schema in my json

module DB STORE = { keyOne: [{id: 1, prop: "bar", vsn: 2, free: 20 }, {id: 2, prop: "foo", vsn: 2, free: 10 }], keyTwo: [{id: 1, prop: "bar"}, {id: 3, prop: "bar"}, {id: 4, prop: "bar"}] } ! def self.find_all keys, prop keys.map { |k| STORE.fetch(k.to_sym, []).map { |e| e if e[:prop] == prop }.compact } end end

Page 39: You got schema in my json

def is_version2? data; data[:vsn] == 2; end def get_free id; 20; end def save data; data; end !def transfrom_to_v2 data return data if is_version2?(data) ! data[:vsn] = 2 data[:free] = calculate_free(data[:id]) save data end

Page 40: You got schema in my json

def get_search_results keys results = DB::find_all(keys, "bar") results.flatten .map { |data| transfrom_to_v2 data } .uniq end !get_search_results ["keyOne", “keyTwo"] !# => [{:id=>1, :prop=>"bar", :vsn=>2, :free=>20}, {:id=>3, :prop=>"bar", :vsn=>2, :free=>20}, {:id=>4, :prop=>"bar", :vsn=>2, :free=>20}]

Page 41: You got schema in my json

DRY it up: Deprecator

https://github.com/sideshowcoder/deprecator

Page 42: You got schema in my json

class Thing def initialize *args args.each do |k, v| self.instance_variable_set "@#{k}", v end @version = 0 unless @version end attr_accessor :version ! include Deprecator::Versioning ensure_version 2, :upgrade_to ! def upgrade_to expected_version # handle the version upgrade save end ! def save # save back to the store end end

Page 43: You got schema in my json

Lessons learned

Page 44: You got schema in my json

Painless data changes are important

Page 45: You got schema in my json

Schemaless does not mean no Schema at all

Page 46: You got schema in my json

With freedom comes more responsibility

Page 47: You got schema in my json

Agile Code needs Agile Data

Page 48: You got schema in my json

Couchbase NoSQL Database

Page 49: You got schema in my json

!

Any Questions?

Philipp Fehre !github.com/sideshowcoder twitter.com/ischi sideshowcoder.com

Page 50: You got schema in my json

Talks to listen to

!

• Schemalessness: http://cloud.dzone.com/articles/martin-fowler-schemalessness

• Introduction to NoSQL: http://www.youtube.com/watch?v=qI_g07C_Q5I