MYSQL TO
MONGO (FTW)
Thinking Differently About Schema Design
@AJSHARP

Alex Sharp
Lead Developer, OptimisCorp

alexjsharp.com

github.com/ajsharp
CVBEAST
Mongo has many cool
features such as schema-
free, aggregation w
map/reduce and many
others
                      ...
CVBEAST

 App to represent people’s curriculum vitae, but not in an
                    academic sense
CVBEAST

 Focus on “micro” experiences not suitable for a typical CV
           (definitely not suitable for a resumé)
CVBEAST

Simple object model, centered around highlighting attributes
                        of a person
CVBEAST

   Started out building with MySQL, b/c it’s familiar
OBJECT MODEL
                 Person

                 has a

                   CV

                has many

           ...
OBJECT MODEL
                           Person

                           has a

                             CV

 links,...
RELATIONAL SCHEMA
         people
           - id
           - name
           - ...

         cvs
           - id
       ...
RELATIONAL SCHEMA


       Lots of pointless JOINs
RELATIONAL SCHEMA
         people
           - id
           - name
           - ...

         cvs
           - id
       ...
RELATIONAL SCHEMA
         people
           - id
           - name
           - ...

         cvs             tags
      ...
not b/c of premature
optimization




                       this bothers me
It misrepresents the object model
        at the storage layer
It also became difficult to work with
 despite my familiarity with MySQL
It makes sense to store object relationships in
     first-class entities/documents/tables
But true object properties should be
        stored as properties
Not relationships.
Especially when properties have no practical
        meaning without the parent
CAVEAT


                              This is not always the case.

                                                    ;...
EXAMPLE
Experience Links
EXPERIENCE.LINKS = [...]

     Dead-simple collection of links attached to
                  an experience
RUBY MODEL CODE
 class Person
   include Mongoid::Document

   field :keywords, :type => Array

   index :keywords
   inde...
class Experience
  include Mongoid::Document

  embeds_many :links
end

class Link
  include Mongoid::Document

  field :u...
class Experience
  include Mongoid::Document

  embeds_many :links
end                    Both models are embedded in the
...
EXPERIENCE.LINKS = [...]

      A link is only relevant inside the
      context of an experience object.
EXPERIENCE.LINKS = [...]

      In other words, it is a property,
            not a relationship.
EXPERIENCE.LINKS = [...]

   Mongo brings the storage layer closer to
             the object model
EXPERIENCE.LINKS = [...]
{
    "title": "Presented at MongoLA",
    "links": [
      { "title": "Event Site",
        "url...
EXAMPLE
Embedded Search
MYSQL
An exercise in masochism
The difficulty in MySQL came in working with
            properties of a person
These properties are represented as tables
And tables must be joined
SIMPLE SEARCH QUERY
select * from people
  inner join cvs on cvs.person_id = people.id
  inner join experiences on experie...
INDEXES NEEDED
 -   tags.experience_id
 -   tags.name
 -   experiences.cv_id
 -   cvs.person_id
Seems extremely unnecessary for such a
         simple object model
MONGO
An exercise in ... not masochism
Embedded objects make this query easy.
MONGO DOCUMENT “SCHEMA”
{"name": "Alex Sharp",
   "cv": {
     "experiences": [
       { "title": "spoke at MongoLA",
    ...
MONGO DOCUMENT “SCHEMA”
{"name": "Alex Sharp",
   "cv": {
     "experiences": [
       { "title": "spoke at MongoLA",
    ...
RUBY MODEL CODE
 class Person
   include Mongoid::Document

   field :keywords, :type => Array

   index :keywords
   inde...
RUBY MODEL CODE
class Cv
  include Mongoid::Document

  embeds_many :experiences
end

class Experience
  include Mongoid::...
RUBY MODEL CODE
class Cv
  include Mongoid::Document
                                      simple property
  embeds_many :...
RUBY SEARCH CODE
class Person

  # i.e. db.people.find({"cv.experiences.tags": "ruby"})
  def self.search_by_tag(term)
   ...
COMPARISON
select * from people
  inner join cvs on cvs.person_id = people.id
  inner join experiences on experiences.cv_i...
WINS: IMPEDENCE MIS-MATCH

   Object persistence format is closer to
         application usage format
WINS: F(X)-ALITY

    Plus, we don’t lose any functionality.
WINS: FAMILIARITY

  Indexing principles are extremely familiar to
           relational database users.
WINS: FAMILIARITY

          Only simpler ;)
WINS: SIMPLICITY

        Query syntax is simple.
WINS: SIMPLICITY

    Dot notation > JOIN semantics filth
SUMMARY

     Mongo is perfectly suited for
        an app like CVBeast.
SUMMARY

   Where a relational DB forces storing
    object properties as relationships
SUMMARY

 Mongo narrows this mismatch considerably
SUMMARY

      A CV is a document...
SUMMARY

   So a document-oriented datastore
          seems appropriate.
SUMMARY

    Many object models have this
        tree-like structure.
SUMMARY

 Be willing to step outside of your comfort zone
SUMMARY

   And use Mongo when it’s practical.
Mysql to mongo
Mysql to mongo
Upcoming SlideShare
Loading in …5
×

Mysql to mongo

6,990 views

Published on

Slides for Presentation given at MongoLA on January 13, 2011 at Media Temple.

Published in: Technology
0 Comments
8 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
6,990
On SlideShare
0
From Embeds
0
Number of Embeds
1,433
Actions
Shares
0
Downloads
67
Comments
0
Likes
8
Embeds 0
No embeds

No notes for slide

Mysql to mongo

  1. 1. MYSQL TO MONGO (FTW) Thinking Differently About Schema Design
  2. 2. @AJSHARP Alex Sharp Lead Developer, OptimisCorp alexjsharp.com github.com/ajsharp
  3. 3. CVBEAST Mongo has many cool features such as schema- free, aggregation w map/reduce and many others Side project interested more in domain modeling more than performance and scaling benefits of Mongo EMBEDDED OBJECTS
  4. 4. CVBEAST App to represent people’s curriculum vitae, but not in an academic sense
  5. 5. CVBEAST Focus on “micro” experiences not suitable for a typical CV (definitely not suitable for a resumé)
  6. 6. CVBEAST Simple object model, centered around highlighting attributes of a person
  7. 7. CVBEAST Started out building with MySQL, b/c it’s familiar
  8. 8. OBJECT MODEL Person has a CV has many Experience has many ... ... ...
  9. 9. OBJECT MODEL Person has a CV links, tags, and has many other arbitrary properties Experience has many ... ... ...
  10. 10. RELATIONAL SCHEMA people - id - name - ... cvs - id - person_id - ... experiences - id - cv_id - ...
  11. 11. RELATIONAL SCHEMA Lots of pointless JOINs
  12. 12. RELATIONAL SCHEMA people - id - name - ... cvs - id - person_id - ... experiences - id - cv_id - ...
  13. 13. RELATIONAL SCHEMA people - id - name - ... cvs tags - id - id - name - person_id - ... - ... links experiences - id - name - id - ... - cv_id - ...
  14. 14. not b/c of premature optimization this bothers me
  15. 15. It misrepresents the object model at the storage layer
  16. 16. It also became difficult to work with despite my familiarity with MySQL
  17. 17. It makes sense to store object relationships in first-class entities/documents/tables
  18. 18. But true object properties should be stored as properties
  19. 19. Not relationships.
  20. 20. Especially when properties have no practical meaning without the parent
  21. 21. CAVEAT This is not always the case. ;-) if you need to: * store LOTS of embedded objects (i.e. papermill)
  22. 22. EXAMPLE Experience Links
  23. 23. EXPERIENCE.LINKS = [...] Dead-simple collection of links attached to an experience
  24. 24. RUBY MODEL CODE class Person include Mongoid::Document field :keywords, :type => Array index :keywords index 'cv.experiences.tags' end
  25. 25. class Experience include Mongoid::Document embeds_many :links end class Link include Mongoid::Document field :url field :title embedded_in :experience, :inverse_of => :links end
  26. 26. class Experience include Mongoid::Document embeds_many :links end Both models are embedded in the person collection class Link include Mongoid::Document field :url field :title embedded_in :experience, :inverse_of => :links end
  27. 27. EXPERIENCE.LINKS = [...] A link is only relevant inside the context of an experience object.
  28. 28. EXPERIENCE.LINKS = [...] In other words, it is a property, not a relationship.
  29. 29. EXPERIENCE.LINKS = [...] Mongo brings the storage layer closer to the object model
  30. 30. EXPERIENCE.LINKS = [...] { "title": "Presented at MongoLA", "links": [ { "title": "Event Site", "url": "http://www.10gen.com/conferences/mongola2011"}, { "title": "Slides", "url": "http://alexjsharp.com/posts/mongola-2010-slides"} ] }
  31. 31. EXAMPLE Embedded Search
  32. 32. MYSQL An exercise in masochism
  33. 33. The difficulty in MySQL came in working with properties of a person
  34. 34. These properties are represented as tables
  35. 35. And tables must be joined
  36. 36. SIMPLE SEARCH QUERY select * from people inner join cvs on cvs.person_id = people.id inner join experiences on experiences.cv_id = cvs.id inner join tags on tags.experience_id = experiences.id where tags.name = 'ruby';
  37. 37. INDEXES NEEDED - tags.experience_id - tags.name - experiences.cv_id - cvs.person_id
  38. 38. Seems extremely unnecessary for such a simple object model
  39. 39. MONGO An exercise in ... not masochism
  40. 40. Embedded objects make this query easy.
  41. 41. MONGO DOCUMENT “SCHEMA” {"name": "Alex Sharp", "cv": { "experiences": [ { "title": "spoke at MongoLA", "date" : "Thu Jan 13 2011", "tags" : ["mongodb", "speaking"] }, {"title": "..."} ] } }
  42. 42. MONGO DOCUMENT “SCHEMA” {"name": "Alex Sharp", "cv": { "experiences": [ { "title": "spoke at MongoLA", "date" : "Thu Jan 13 2011", "tags" : ["mongodb", "speaking"] }, {"title": "..."} ] } } we want to search for these
  43. 43. RUBY MODEL CODE class Person include Mongoid::Document field :keywords, :type => Array index :keywords index 'cv.experiences.tags' end
  44. 44. RUBY MODEL CODE class Cv include Mongoid::Document embeds_many :experiences end class Experience include Mongoid::Document field :tags, :type => Array, :default => [] embedded_in :cv, :inverse_of => :experiences embeds_many :links after_save lambda { |exp| exp.cv.person.update_keywords } end
  45. 45. RUBY MODEL CODE class Cv include Mongoid::Document simple property embeds_many :experiences end (not relationship) class Experience include Mongoid::Document field :tags, :type => Array, :default => [] embedded_in :cv, :inverse_of => :experiences embeds_many :links after_save lambda { |exp| exp.cv.person.update_keywords } end
  46. 46. RUBY SEARCH CODE class Person # i.e. db.people.find({"cv.experiences.tags": "ruby"}) def self.search_by_tag(term) collection.find('cv.experiences.tags' => 'ruby') end end
  47. 47. COMPARISON select * from people inner join cvs on cvs.person_id = people.id inner join experiences on experiences.cv_id = cvs.id inner join tags on tags.experience_id = experiences.id where tags.name = 'ruby'; vs db.people.find('cv.experiences.tags' => 'ruby')
  48. 48. WINS: IMPEDENCE MIS-MATCH Object persistence format is closer to application usage format
  49. 49. WINS: F(X)-ALITY Plus, we don’t lose any functionality.
  50. 50. WINS: FAMILIARITY Indexing principles are extremely familiar to relational database users.
  51. 51. WINS: FAMILIARITY Only simpler ;)
  52. 52. WINS: SIMPLICITY Query syntax is simple.
  53. 53. WINS: SIMPLICITY Dot notation > JOIN semantics filth
  54. 54. SUMMARY Mongo is perfectly suited for an app like CVBeast.
  55. 55. SUMMARY Where a relational DB forces storing object properties as relationships
  56. 56. SUMMARY Mongo narrows this mismatch considerably
  57. 57. SUMMARY A CV is a document...
  58. 58. SUMMARY So a document-oriented datastore seems appropriate.
  59. 59. SUMMARY Many object models have this tree-like structure.
  60. 60. SUMMARY Be willing to step outside of your comfort zone
  61. 61. SUMMARY And use Mongo when it’s practical.

×