Schema Design with MongoDB

open-source, high-performance,
  document-oriented database
Schema Design Basics
    roger@10Gen.com
This talk
This talk
‣Intro
  -Terms / Definitions
This talk
‣Intro
  -Terms / Definitions
This talk
‣Intro
  -Terms / Definitions
‣Getting a flavor
 -Creating a Schema
 -Indexes
 -Evolving the Schema
This talk
‣Intro
  -Terms / Definitions
‣Getting a flavor
 -Creating a Schema
 -Indexes
 -Evolving the Schema
‣Data modeling
 -DBRef
 -Single Table Inheritance
 -Many - Many
 -Trees
 -Lists / Queues / Stacks
Document Oriented

Basic unit of data: JSON Documents
Not Relational, Key Value

Not OODB
 - Associations implied by Document Structure
 - but your database schema != your program schema
Terms
Table           -> Collection

Row(s)          -> JSON Document

Index           -> Index

Join            -> Embedding and Linking
                   across documents

Partition       -> Shard
Partition Key   -> Shard Key
Considerations

What are the requirements ?
 - Functionality to be supported
 - Access Patterns ?
 - Data Life Cycle (insert, update, deletes)
 - Expected Performance / Workload ?

Capabilities of the database ?
DB Considerations
How can we manipulate this data ?
 Dynamic Queries
 Secondary Indexes
 Atomic Updates
 Map Reduce

Access Patterns ?
  Read / Write Ratio
  Types of updates
  Types of queries

Considerations
 No Joins
 Single Document Transactions only
Design Session
Use Rich Design Documents

 post = {author: “kyle”,
      date: new Date(),
      text: “my blog post...”,
      tags: [“mongodb”, “intro”]}

 >db.post.save(post)
>db.posts.find()

 { _id : ObjectId("4c4ba5c0672c685e5e8aabf3"),
   author : "kyle",
   date : "Sat Jul 24 2010 19:47:11 GMT-0700 (PDT)",
   text : "My first blog",
   tags : [ "mongodb", "intro" ] }

Notes:
 - ID is unique, but can be anything you’d like
Secondary index for “author”

 // 1 means ascending, -1 means descending

 >db.posts.ensureIndex({author: 1})

 >db.posts.find({author: 'kyle'})

 { _id    : ObjectId("4c4ba5c0672c685e5e8aabf3"),
   author : "kyle",
   ... }
Verifying indexes exist
 >db.system.indexes.find()

   // Index on ID
   { name : "_id_",
     ns : "test.posts",
     key : { "_id" : 1 } }
Verifying indexes exist
 >db.system.indexes.find()

   // Index on ID
   { name : "_id_",
     ns : "test.posts",
     key : { "_id" : 1 } }

   // Index on author
   { _id : ObjectId("4c4ba6c5672c685e5e8aabf4"),
     ns : "test.posts",
     key : { "author" : 1 },
     name : "author_1" }
Query operators
Conditional operators:
 $ne, $in, $nin, $mod, $all, $size, $exists, $type, ..
 $lt, $lte, $gt, $gte, $ne,

  // find posts with any tags
  >db.posts.find({tags: {$exists: true}})
Query operators
Conditional operators:
 $ne, $in, $nin, $mod, $all, $size, $exists, $type, ..
 $lt, $lte, $gt, $gte, $ne,

  // find posts with any tags
  >db.posts.find({tags: {$exists: true}})

Regular expressions:
   // posts where author starts with k
   >db.posts.find({author: /^k*/i })
Query operators
Conditional operators:
 $ne, $in, $nin, $mod, $all, $size, $exists, $type, ..
 $lt, $lte, $gt, $gte, $ne,

  // find posts with any tags
  >db.posts.find({tags: {$exists: true}})

Regular expressions:
   // posts where author starts with k
   >db.posts.find({author: /^k*/i })

Counting:
   // posts written by mike
  >db.posts.find({author: “mike”}).count()
Extending the Schema
 comment = {author: “fred”,
            date: new Date(),
            text: “super duper”}

 update = { ‘$push’: {comments: comment},
            ‘$inc’: {comments_count: 1}}

 >db.posts.update({_id: “...” }, update)
{ _id : ObjectId("4c4ba5c0672c685e5e8aabf3"),
      author : "kyle",
      date : "Sat Jul 24 2010 19:47:11 GMT-0700 (PDT)",
      text : "My first blog",
      tags : [ "mongodb", "intro" ],
      comments_count: 1,
      comments : [

      {

      
 author : "Fred",

      
 date : "Sat Jul 24 2010 20:51:03 GMT-0700 (PDT)",

      
 text : "Super Duper"

      }
      ]}
// create index on nested documents:
>db.posts.ensureIndex({"comments.author": 1})

>db.posts.find({comments.author:”Fred”})
// create index on nested documents:
>db.posts.ensureIndex({"comments.author": 1})

>db.posts.find({comments.author:”kyle”})

// find last 5 posts:
>db.posts.find().sort({date:-1}).limit(5)
// create index on nested documents:
>db.posts.ensureIndex({"comments.author": 1})

>db.posts.find({comments.author:”kyle”})

// find last 5 posts:
>db.posts.find().sort({date:-1}).limit(5)

// most commented post:
 >db.posts.find().sort({comments_count:-1}).limit(1)

When sorting, check if you need an index
Map Reduce
Aggregation and batch manipulation

 Collection in, Collection out

 Parallel in sharded environments
Map reduce
mapFunc = function () {
  this.tags.forEach(function (z) {emit(z, {count:1});});
}

reduceFunc = function (k, v) {
  var total = 0;
  for (var i = 0; i < v.length; i++) { total += v[i].count; }
  return {count:total}; }

res = db.posts.mapReduce(mapFunc, reduceFunc)

>db[res.result].find()
  { _id : "intro", value : { count : 1 } }
  { _id : "mongodb", value : { count : 1 } }
Review
So Far:
- Started out with a simple schema
- Queried Data
- Evolved the schema
- Queried / Updated the data some more
Wordnik
9B   records, 100M queries / week, 1,2TB
{

     entry : {

     
   header: { id: 0,

     
   
     headword: "m",

     
   
     sourceDictionary: "GCide",

     
   
     textProns : [

     
   
       {text: "(em)",

     
   
        seq:0}

     
   
     ],

     
   
     syllables: [

     
   
     
    {id: 0,

     
   
         text: "m"}

     
   
     ],

     
   

     
   
     sourceDictionary: "1913 Webster",

     
   
     headWord: "m",

     
   
     id: 1,

     
   
     definitions: : [

     
   
       {text: "M, the thirteenth letter..."},

     
   
       {text: "As a numeral, M stands for 1000"}]

     
   
     }

     }
}
Review
So Far:
- Started out with a simple schema
- Queried Data
- Evolved the schema
- Queried / Updated the data some more

Observations:
- Using Rich Documents works well
- Simplify relations by embedding them
- Iterative development is easy with MongoDB
Schema Design with MongoDB
Single Table Inheritance
>db.shapes.find()

 { _id: ObjectId("..."), type: "circle", area: 3.14, radius: 1}
 { _id: ObjectId("..."), type: "square", area: 4,    d: 2}
 { _id: ObjectId("..."), type: "rect",   area: 10, length: 5, width: 2}

// find shapes where radius > 0
>db.shapes.find({radius: {$gt: 0}})

// create index
>db.shapes.ensureIndex({radius: 1})
One to Many
- Embedded Array / Array Keys
  - slice operator to return subset of array
  - hard to find latest comments across all documents
One to Many
- Embedded Array / Array Keys
  - slice operator to return subset of array
  - hard to find latest comments across all documents

- Embedded tree
  - Single document
  - Natural
  - Hard to query
One to Many
- Embedded Array / Array Keys
  - slice operator to return subset of array
  - hard to find latest comments across all documents

- Embedded tree
  - Single document
  - Natural
  - Hard to query

- Normalized (2 collections)
  - most flexible
  - more queries
Many - Many
Example:

- Product can be in many categories
- Category can have many products



  Products     id | product_id | category_id   Category
products:
  { _id: ObjectId("4c4ca23933fb5941681b912e"),
    name: "Sumatra Dark Roast",
    category_ids: [ ObjectId("4c4ca25433fb5941681b912f"),
                    ObjectId("4c4ca25433fb5941681b92af”]}
products:
  { _id: ObjectId("4c4ca23933fb5941681b912e"),
    name: "Sumatra Dark Roast",
    category_ids: [ ObjectId("4c4ca25433fb5941681b912f"),
                    ObjectId("4c4ca25433fb5941681b92af”]}

categories:
  { _id: ObjectId("4c4ca25433fb5941681b912f"),
    name: "Indonesia",
    product_ids: [ ObjectId("4c4ca23933fb5941681b912e"),
                   ObjectId("4c4ca30433fb5941681b9130"),
                   ObjectId("4c4ca30433fb5941681b913a"]}
products:
  { _id: ObjectId("4c4ca23933fb5941681b912e"),
    name: "Sumatra Dark Roast",
    category_ids: [ ObjectId("4c4ca25433fb5941681b912f"),
                    ObjectId("4c4ca25433fb5941681b92af”]}

categories:
  { _id: ObjectId("4c4ca25433fb5941681b912f"),
    name: "Indonesia",
    product_ids: [ ObjectId("4c4ca23933fb5941681b912e"),
                   ObjectId("4c4ca30433fb5941681b9130"),
                   ObjectId("4c4ca30433fb5941681b913a"]}

//All categories for a given product
>db.categories.find({product_ids: ObjectId("4c4ca23933fb5941681b912e")})
products:
  { _id: ObjectId("4c4ca23933fb5941681b912e"),
    name: "Sumatra Dark Roast",
    category_ids: [ ObjectId("4c4ca25433fb5941681b912f"),
                    ObjectId("4c4ca25433fb5941681b92af”]}

categories:
  { _id: ObjectId("4c4ca25433fb5941681b912f"),
    name: "Indonesia",
    product_ids: [ ObjectId("4c4ca23933fb5941681b912e"),
                   ObjectId("4c4ca30433fb5941681b9130"),
                   ObjectId("4c4ca30433fb5941681b913a"]}

//All categories for a given product
>db.categories.find({product_ids: ObjectId("4c4ca23933fb5941681b912e")})

//All products for a given category
>db.products.find({category_ids: ObjectId("4c4ca25433fb5941681b912f")})
Alternative
products:
  { _id: ObjectId("4c4ca23933fb5941681b912e"),
    name: "Sumatra Dark Roast",
    category_ids: [ ObjectId("4c4ca25433fb5941681b912f"),
                    ObjectId("4c4ca25433fb5941681b92af”]}

categories:
  { _id: ObjectId("4c4ca25433fb5941681b912f"),
    name: "Indonesia"}
Alternative
products:
  { _id: ObjectId("4c4ca23933fb5941681b912e"),
    name: "Sumatra Dark Roast",
    category_ids: [ ObjectId("4c4ca25433fb5941681b912f"),
                    ObjectId("4c4ca25433fb5941681b92af”]}

categories:
  { _id: ObjectId("4c4ca25433fb5941681b912f"),
    name: "Indonesia"}

// All products for a given category
>db.products.find({category_ids: ObjectId("4c4ca25433fb5941681b912f")})
Alternative
products:
  { _id: ObjectId("4c4ca23933fb5941681b912e"),
    name: "Sumatra Dark Roast",
    category_ids: [ ObjectId("4c4ca25433fb5941681b912f"),
                    ObjectId("4c4ca25433fb5941681b92af”]}

categories:
  { _id: ObjectId("4c4ca25433fb5941681b912f"),
    name: "Indonesia"}

// All products for a given category
>db.products.find({category_ids: ObjectId("4c4ca25433fb5941681b912f")})

// All categories for a given product
product = db.products.find(_id : some_id)
>db.categories.find({_id : {$in : product.category_ids}})
Trees
Full Tree in Document

{ comments: [
     { author: “rpb”, text: “...”,
       replies: [
                  {author: “Fred”, text: “...”,
                   replies: []}
       ]}
   ]}

  Pros: Single Document, Performance, Intuitive
  Cons: Hard to search, Partial Results, 4MB limit
Trees
Parent Links
- Each node is stored as a document
- Contains the id of the parent

Child Links
- Each node contains the id’s of the children
- Can support graphs (multiple parents / child)
Array of Ancestors
- Store Ancestors of a node
 {   _id:   "a" }
 {   _id:   "b", ancestors: [ "a" ], parent: "a" }
 {   _id:   "c", ancestors: [ "a", "b" ], parent: "b" }
 {   _id:   "d", ancestors: [ "a", "b" ], parent: "b" }
 {   _id:   "e", ancestors: [ "a" ], parent: "a" }
 {   _id:   "f", ancestors: [ "a", "e" ], parent: "e" }
 {   _id:   "g", ancestors: [ "a", "b", "d" ], parent: "d" }
Array of Ancestors
- Store Ancestors of a node
 {   _id:   "a" }
 {   _id:   "b", ancestors: [ "a" ], parent: "a" }
 {   _id:   "c", ancestors: [ "a", "b" ], parent: "b" }
 {   _id:   "d", ancestors: [ "a", "b" ], parent: "b" }
 {   _id:   "e", ancestors: [ "a" ], parent: "a" }
 {   _id:   "f", ancestors: [ "a", "e" ], parent: "e" }
 {   _id:   "g", ancestors: [ "a", "b", "d" ], parent: "d" }

//find all descendants of b:
>db.tree2.find({ancestors: ‘b’})
Array of Ancestors
- Store Ancestors of a node
 {   _id:   "a" }
 {   _id:   "b", ancestors: [ "a" ], parent: "a" }
 {   _id:   "c", ancestors: [ "a", "b" ], parent: "b" }
 {   _id:   "d", ancestors: [ "a", "b" ], parent: "b" }
 {   _id:   "e", ancestors: [ "a" ], parent: "a" }
 {   _id:   "f", ancestors: [ "a", "e" ], parent: "e" }
 {   _id:   "g", ancestors: [ "a", "b", "d" ], parent: "d" }

//find all descendants of b:
>db.tree2.find({ancestors: ‘b’})

//find all ancestors of f:
>ancestors = db.tree2.findOne({_id:’f’}).ancestors
>db.tree2.find({_id: { $in : ancestors})
findAndModify
Queue example

//Example: grab highest priority job and mark

job = db.jobs.findAndModify({
          query: {inprogress: false},
          sort:   {priority: -1),
          update: {$set: {inprogress: true,
                          started: new Date()}},
          new: true})
More Cool Stuff

• Aggregation
• Capped collections
• GridFS
• Geo
Learn More
 Kyle’s presentation + video:
http://www.slideshare.net/kbanker/mongodb-schema-design
http://www.blip.tv/file/3704083

 Dwight’s presentation
http://www.slideshare.net/mongosf/schema-design-with-mongodb-dwight-
merriman

 Documentation
Trees:   http://www.mongodb.org/display/DOCS/Trees+in+MongoDB
Queues: http://www.mongodb.org/display/DOCS/findandmodify+Command
Aggregration: http://www.mongodb.org/display/DOCS/Aggregation
Capped Col. : http://www.mongodb.org/display/DOCS/Capped+Collections
Geo: http://www.mongodb.org/display/DOCS/Geospatial+Indexing
GridFS: http://www.mongodb.org/display/DOCS/GridFS+Specification
Thank You :-)
Download
       MongoDB

and let us know what you think
          @mongodb
   http://www.mongodb.org
DBRef
DBRef
 {$ref: collection, $id: id_value}

- Think URL
- YDSMV: your driver support may vary

Sample Schema:
  nr = {note_refs: [{"$ref" : "notes", "$id" : 5}, ... ]}

Dereferencing:
  nr.forEach(function(r) {
    printjson(db[r.$ref].findOne({_id: r.$id}));
  }
BSON
Mongodb stores data in BSON internally

 Lightweight, Traversable, Efficient encoding

 Typed
   boolean, integer, float, date, string, binary, array...
1 of 54

Recommended

Building a Scalable Inbox System with MongoDB and Java by
Building a Scalable Inbox System with MongoDB and JavaBuilding a Scalable Inbox System with MongoDB and Java
Building a Scalable Inbox System with MongoDB and Javaantoinegirbal
6.7K views48 slides
MongoDB Schema Design by
MongoDB Schema DesignMongoDB Schema Design
MongoDB Schema DesignAlex Litvinok
30.9K views31 slides
Webinar: Schema Design by
Webinar: Schema DesignWebinar: Schema Design
Webinar: Schema DesignMongoDB
28.9K views46 slides
Dev Jumpstart: Schema Design Best Practices by
Dev Jumpstart: Schema Design Best PracticesDev Jumpstart: Schema Design Best Practices
Dev Jumpstart: Schema Design Best PracticesMongoDB
1.4K views45 slides
Mongo DB schema design patterns by
Mongo DB schema design patternsMongo DB schema design patterns
Mongo DB schema design patternsjoergreichert
2.6K views27 slides
Building web applications with mongo db presentation by
Building web applications with mongo db presentationBuilding web applications with mongo db presentation
Building web applications with mongo db presentationMurat Çakal
4.3K views30 slides

More Related Content

What's hot

MongoDB Schema Design by
MongoDB Schema DesignMongoDB Schema Design
MongoDB Schema DesignMongoDB
25.5K views44 slides
Webinar: Back to Basics: Thinking in Documents by
Webinar: Back to Basics: Thinking in DocumentsWebinar: Back to Basics: Thinking in Documents
Webinar: Back to Basics: Thinking in DocumentsMongoDB
107.6K views58 slides
Building your first app with mongo db by
Building your first app with mongo dbBuilding your first app with mongo db
Building your first app with mongo dbMongoDB
4.4K views53 slides
Schema Design by Example ~ MongoSF 2012 by
Schema Design by Example ~ MongoSF 2012Schema Design by Example ~ MongoSF 2012
Schema Design by Example ~ MongoSF 2012hungarianhc
6K views40 slides
Agile Schema Design: An introduction to MongoDB by
Agile Schema Design: An introduction to MongoDBAgile Schema Design: An introduction to MongoDB
Agile Schema Design: An introduction to MongoDBStephen Steneker
2.4K views58 slides
Back to Basics Webinar 3: Schema Design Thinking in Documents by
 Back to Basics Webinar 3: Schema Design Thinking in Documents Back to Basics Webinar 3: Schema Design Thinking in Documents
Back to Basics Webinar 3: Schema Design Thinking in DocumentsMongoDB
3.6K views21 slides

What's hot(19)

MongoDB Schema Design by MongoDB
MongoDB Schema DesignMongoDB Schema Design
MongoDB Schema Design
MongoDB25.5K views
Webinar: Back to Basics: Thinking in Documents by MongoDB
Webinar: Back to Basics: Thinking in DocumentsWebinar: Back to Basics: Thinking in Documents
Webinar: Back to Basics: Thinking in Documents
MongoDB107.6K views
Building your first app with mongo db by MongoDB
Building your first app with mongo dbBuilding your first app with mongo db
Building your first app with mongo db
MongoDB4.4K views
Schema Design by Example ~ MongoSF 2012 by hungarianhc
Schema Design by Example ~ MongoSF 2012Schema Design by Example ~ MongoSF 2012
Schema Design by Example ~ MongoSF 2012
hungarianhc6K views
Agile Schema Design: An introduction to MongoDB by Stephen Steneker
Agile Schema Design: An introduction to MongoDBAgile Schema Design: An introduction to MongoDB
Agile Schema Design: An introduction to MongoDB
Stephen Steneker2.4K views
Back to Basics Webinar 3: Schema Design Thinking in Documents by MongoDB
 Back to Basics Webinar 3: Schema Design Thinking in Documents Back to Basics Webinar 3: Schema Design Thinking in Documents
Back to Basics Webinar 3: Schema Design Thinking in Documents
MongoDB3.6K views
Back to Basics 1: Thinking in documents by MongoDB
Back to Basics 1: Thinking in documentsBack to Basics 1: Thinking in documents
Back to Basics 1: Thinking in documents
MongoDB33.9K views
Building Apps with MongoDB by Nate Abele
Building Apps with MongoDBBuilding Apps with MongoDB
Building Apps with MongoDB
Nate Abele9.3K views
MongoDB Advanced Schema Design - Inboxes by Jared Rosoff
MongoDB Advanced Schema Design - InboxesMongoDB Advanced Schema Design - Inboxes
MongoDB Advanced Schema Design - Inboxes
Jared Rosoff20.7K views
The Fine Art of Schema Design in MongoDB: Dos and Don'ts by Matias Cascallares
The Fine Art of Schema Design in MongoDB: Dos and Don'tsThe Fine Art of Schema Design in MongoDB: Dos and Don'ts
The Fine Art of Schema Design in MongoDB: Dos and Don'ts
Matias Cascallares4.2K views
Why MongoDB is awesome by John Nunemaker
Why MongoDB is awesomeWhy MongoDB is awesome
Why MongoDB is awesome
John Nunemaker79.2K views
Data Modeling for the Real World by Mike Friedman
Data Modeling for the Real WorldData Modeling for the Real World
Data Modeling for the Real World
Mike Friedman1.1K views
10gen Presents Schema Design and Data Modeling by DATAVERSITY
10gen Presents Schema Design and Data Modeling10gen Presents Schema Design and Data Modeling
10gen Presents Schema Design and Data Modeling
DATAVERSITY1.2K views
Webinar: Data Modeling Examples in the Real World by MongoDB
Webinar: Data Modeling Examples in the Real WorldWebinar: Data Modeling Examples in the Real World
Webinar: Data Modeling Examples in the Real World
MongoDB5.1K views
Building a Social Network with MongoDB by Fred Chu
  Building a Social Network with MongoDB  Building a Social Network with MongoDB
Building a Social Network with MongoDB
Fred Chu9.2K views
Modeling Data in MongoDB by lehresman
Modeling Data in MongoDBModeling Data in MongoDB
Modeling Data in MongoDB
lehresman11.4K views
Back to Basics Webinar 4: Advanced Indexing, Text and Geospatial Indexes by MongoDB
Back to Basics Webinar 4: Advanced Indexing, Text and Geospatial IndexesBack to Basics Webinar 4: Advanced Indexing, Text and Geospatial Indexes
Back to Basics Webinar 4: Advanced Indexing, Text and Geospatial Indexes
MongoDB5.5K views
Intro to MongoDB and datamodeling by rogerbodamer
Intro to MongoDB and datamodeling Intro to MongoDB and datamodeling
Intro to MongoDB and datamodeling
rogerbodamer1.5K views
Socialite, the Open Source Status Feed by MongoDB
Socialite, the Open Source Status FeedSocialite, the Open Source Status Feed
Socialite, the Open Source Status Feed
MongoDB3.4K views

Viewers also liked

Business Metrics and Web Marketing by
Business Metrics and Web MarketingBusiness Metrics and Web Marketing
Business Metrics and Web MarketingAlper AKBAS
799 views92 slides
Dimensional Modeling by
Dimensional ModelingDimensional Modeling
Dimensional ModelingSunita Sahu
19.4K views50 slides
World-Class Web Metrics by Dan Olsen by
World-Class Web Metrics by Dan OlsenWorld-Class Web Metrics by Dan Olsen
World-Class Web Metrics by Dan OlsenDan Olsen
12.6K views42 slides
Web analytics 101: Web Metrics by
Web analytics 101: Web MetricsWeb analytics 101: Web Metrics
Web analytics 101: Web MetricsSociety_Consulting
1.7K views32 slides
Dimensional Modeling Basic Concept with Example by
Dimensional Modeling Basic Concept with ExampleDimensional Modeling Basic Concept with Example
Dimensional Modeling Basic Concept with ExampleSajjad Zaheer
24.6K views35 slides
Web Metrics vs Web Behavioral Analytics and Why You Need to Know the Difference by
Web Metrics vs Web Behavioral Analytics and Why You Need to Know the DifferenceWeb Metrics vs Web Behavioral Analytics and Why You Need to Know the Difference
Web Metrics vs Web Behavioral Analytics and Why You Need to Know the DifferenceAlterian
5.4K views41 slides

Viewers also liked(12)

Business Metrics and Web Marketing by Alper AKBAS
Business Metrics and Web MarketingBusiness Metrics and Web Marketing
Business Metrics and Web Marketing
Alper AKBAS799 views
Dimensional Modeling by Sunita Sahu
Dimensional ModelingDimensional Modeling
Dimensional Modeling
Sunita Sahu19.4K views
World-Class Web Metrics by Dan Olsen by Dan Olsen
World-Class Web Metrics by Dan OlsenWorld-Class Web Metrics by Dan Olsen
World-Class Web Metrics by Dan Olsen
Dan Olsen12.6K views
Dimensional Modeling Basic Concept with Example by Sajjad Zaheer
Dimensional Modeling Basic Concept with ExampleDimensional Modeling Basic Concept with Example
Dimensional Modeling Basic Concept with Example
Sajjad Zaheer24.6K views
Web Metrics vs Web Behavioral Analytics and Why You Need to Know the Difference by Alterian
Web Metrics vs Web Behavioral Analytics and Why You Need to Know the DifferenceWeb Metrics vs Web Behavioral Analytics and Why You Need to Know the Difference
Web Metrics vs Web Behavioral Analytics and Why You Need to Know the Difference
Alterian5.4K views
Data Visualization and Dashboard Design by Jacques Warren
Data Visualization and Dashboard DesignData Visualization and Dashboard Design
Data Visualization and Dashboard Design
Jacques Warren22.3K views
Dimensional Modeling by aksrauf
Dimensional ModelingDimensional Modeling
Dimensional Modeling
aksrauf10.2K views
OLAP & DATA WAREHOUSE by Zalpa Rathod
OLAP & DATA WAREHOUSEOLAP & DATA WAREHOUSE
OLAP & DATA WAREHOUSE
Zalpa Rathod73.2K views
Data warehouse-dimensional-modeling-and-design by Sarita Kataria
Data warehouse-dimensional-modeling-and-designData warehouse-dimensional-modeling-and-design
Data warehouse-dimensional-modeling-and-design
Sarita Kataria5.6K views
Multi dimensional model vs (1) by JamesDempsey1
Multi dimensional model vs (1)Multi dimensional model vs (1)
Multi dimensional model vs (1)
JamesDempsey114.7K views

Similar to Schema Design with MongoDB

Webinar: General Technical Overview of MongoDB for Dev Teams by
Webinar: General Technical Overview of MongoDB for Dev TeamsWebinar: General Technical Overview of MongoDB for Dev Teams
Webinar: General Technical Overview of MongoDB for Dev TeamsMongoDB
4.8K views75 slides
Starting with MongoDB by
Starting with MongoDBStarting with MongoDB
Starting with MongoDBDoThinger
621 views18 slides
Schema design short by
Schema design shortSchema design short
Schema design shortMongoDB
2.2K views38 slides
Schema design by
Schema designSchema design
Schema designchristkv
731 views67 slides
Managing Social Content with MongoDB by
Managing Social Content with MongoDBManaging Social Content with MongoDB
Managing Social Content with MongoDBMongoDB
2.2K views47 slides
Schema Design (Mongo Austin) by
Schema Design (Mongo Austin)Schema Design (Mongo Austin)
Schema Design (Mongo Austin)MongoDB
715 views56 slides

Similar to Schema Design with MongoDB(20)

Webinar: General Technical Overview of MongoDB for Dev Teams by MongoDB
Webinar: General Technical Overview of MongoDB for Dev TeamsWebinar: General Technical Overview of MongoDB for Dev Teams
Webinar: General Technical Overview of MongoDB for Dev Teams
MongoDB4.8K views
Starting with MongoDB by DoThinger
Starting with MongoDBStarting with MongoDB
Starting with MongoDB
DoThinger621 views
Schema design short by MongoDB
Schema design shortSchema design short
Schema design short
MongoDB2.2K views
Schema design by christkv
Schema designSchema design
Schema design
christkv731 views
Managing Social Content with MongoDB by MongoDB
Managing Social Content with MongoDBManaging Social Content with MongoDB
Managing Social Content with MongoDB
MongoDB2.2K views
Schema Design (Mongo Austin) by MongoDB
Schema Design (Mongo Austin)Schema Design (Mongo Austin)
Schema Design (Mongo Austin)
MongoDB715 views
Mongodb intro by christkv
Mongodb introMongodb intro
Mongodb intro
christkv4.1K views
MongoDB for Coder Training (Coding Serbia 2013) by Uwe Printz
MongoDB for Coder Training (Coding Serbia 2013)MongoDB for Coder Training (Coding Serbia 2013)
MongoDB for Coder Training (Coding Serbia 2013)
Uwe Printz4.2K views
Dev Jumpstart: Build Your First App with MongoDB by MongoDB
Dev Jumpstart: Build Your First App with MongoDBDev Jumpstart: Build Your First App with MongoDB
Dev Jumpstart: Build Your First App with MongoDB
MongoDB1.5K views
2013-03-23 - NoSQL Spartakiade by Johannes Hoppe
2013-03-23 - NoSQL Spartakiade2013-03-23 - NoSQL Spartakiade
2013-03-23 - NoSQL Spartakiade
Johannes Hoppe1.8K views
Benefits of using MongoDB: Reduce Complexity & Adapt to Changes by Alex Nguyen
Benefits of using MongoDB: Reduce Complexity & Adapt to ChangesBenefits of using MongoDB: Reduce Complexity & Adapt to Changes
Benefits of using MongoDB: Reduce Complexity & Adapt to Changes
Alex Nguyen6.8K views
Building Your First MongoDB App by Henrik Ingo
Building Your First MongoDB AppBuilding Your First MongoDB App
Building Your First MongoDB App
Henrik Ingo1.5K views
Building your first app with MongoDB by Norberto Leite
Building your first app with MongoDBBuilding your first app with MongoDB
Building your first app with MongoDB
Norberto Leite974 views
Back to Basics Webinar 2: Your First MongoDB Application by MongoDB
Back to Basics Webinar 2: Your First MongoDB ApplicationBack to Basics Webinar 2: Your First MongoDB Application
Back to Basics Webinar 2: Your First MongoDB Application
MongoDB4.4K views
Back to Basics Webinar 2 - Your First MongoDB Application by Joe Drumgoole
Back to  Basics Webinar 2 - Your First MongoDB ApplicationBack to  Basics Webinar 2 - Your First MongoDB Application
Back to Basics Webinar 2 - Your First MongoDB Application
Joe Drumgoole292 views
Aggregation Framework MongoDB Days Munich by Norberto Leite
Aggregation Framework MongoDB Days MunichAggregation Framework MongoDB Days Munich
Aggregation Framework MongoDB Days Munich
Norberto Leite2K views

Recently uploaded

TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensors by
TouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective SensorsTouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective Sensors
TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensorssugiuralab
23 views15 slides
Zero to Automated in Under a Year by
Zero to Automated in Under a YearZero to Automated in Under a Year
Zero to Automated in Under a YearNetwork Automation Forum
22 views23 slides
"Node.js Development in 2024: trends and tools", Nikita Galkin by
"Node.js Development in 2024: trends and tools", Nikita Galkin "Node.js Development in 2024: trends and tools", Nikita Galkin
"Node.js Development in 2024: trends and tools", Nikita Galkin Fwdays
17 views38 slides
Data Integrity for Banking and Financial Services by
Data Integrity for Banking and Financial ServicesData Integrity for Banking and Financial Services
Data Integrity for Banking and Financial ServicesPrecisely
29 views26 slides
Ransomware is Knocking your Door_Final.pdf by
Ransomware is Knocking your Door_Final.pdfRansomware is Knocking your Door_Final.pdf
Ransomware is Knocking your Door_Final.pdfSecurity Bootcamp
66 views46 slides
SAP Automation Using Bar Code and FIORI.pdf by
SAP Automation Using Bar Code and FIORI.pdfSAP Automation Using Bar Code and FIORI.pdf
SAP Automation Using Bar Code and FIORI.pdfVirendra Rai, PMP
25 views38 slides

Recently uploaded(20)

TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensors by sugiuralab
TouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective SensorsTouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective Sensors
TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensors
sugiuralab23 views
"Node.js Development in 2024: trends and tools", Nikita Galkin by Fwdays
"Node.js Development in 2024: trends and tools", Nikita Galkin "Node.js Development in 2024: trends and tools", Nikita Galkin
"Node.js Development in 2024: trends and tools", Nikita Galkin
Fwdays17 views
Data Integrity for Banking and Financial Services by Precisely
Data Integrity for Banking and Financial ServicesData Integrity for Banking and Financial Services
Data Integrity for Banking and Financial Services
Precisely29 views
SAP Automation Using Bar Code and FIORI.pdf by Virendra Rai, PMP
SAP Automation Using Bar Code and FIORI.pdfSAP Automation Using Bar Code and FIORI.pdf
SAP Automation Using Bar Code and FIORI.pdf
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLive by Network Automation Forum
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLiveAutomating a World-Class Technology Conference; Behind the Scenes of CiscoLive
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLive
Business Analyst Series 2023 - Week 3 Session 5 by DianaGray10
Business Analyst Series 2023 -  Week 3 Session 5Business Analyst Series 2023 -  Week 3 Session 5
Business Analyst Series 2023 - Week 3 Session 5
DianaGray10345 views
Case Study Copenhagen Energy and Business Central.pdf by Aitana
Case Study Copenhagen Energy and Business Central.pdfCase Study Copenhagen Energy and Business Central.pdf
Case Study Copenhagen Energy and Business Central.pdf
Aitana17 views
PharoJS - Zürich Smalltalk Group Meetup November 2023 by Noury Bouraqadi
PharoJS - Zürich Smalltalk Group Meetup November 2023PharoJS - Zürich Smalltalk Group Meetup November 2023
PharoJS - Zürich Smalltalk Group Meetup November 2023
Noury Bouraqadi139 views
ESPC 2023 - Protect and Govern your Sensitive Data with Microsoft Purview in ... by Jasper Oosterveld
ESPC 2023 - Protect and Govern your Sensitive Data with Microsoft Purview in ...ESPC 2023 - Protect and Govern your Sensitive Data with Microsoft Purview in ...
ESPC 2023 - Protect and Govern your Sensitive Data with Microsoft Purview in ...
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas... by Bernd Ruecker
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
Bernd Ruecker48 views

Schema Design with MongoDB

  • 1. open-source, high-performance, document-oriented database
  • 2. Schema Design Basics roger@10Gen.com
  • 4. This talk ‣Intro -Terms / Definitions
  • 5. This talk ‣Intro -Terms / Definitions
  • 6. This talk ‣Intro -Terms / Definitions ‣Getting a flavor -Creating a Schema -Indexes -Evolving the Schema
  • 7. This talk ‣Intro -Terms / Definitions ‣Getting a flavor -Creating a Schema -Indexes -Evolving the Schema ‣Data modeling -DBRef -Single Table Inheritance -Many - Many -Trees -Lists / Queues / Stacks
  • 8. Document Oriented Basic unit of data: JSON Documents Not Relational, Key Value Not OODB - Associations implied by Document Structure - but your database schema != your program schema
  • 9. Terms Table -> Collection Row(s) -> JSON Document Index -> Index Join -> Embedding and Linking across documents Partition -> Shard Partition Key -> Shard Key
  • 10. Considerations What are the requirements ? - Functionality to be supported - Access Patterns ? - Data Life Cycle (insert, update, deletes) - Expected Performance / Workload ? Capabilities of the database ?
  • 11. DB Considerations How can we manipulate this data ? Dynamic Queries Secondary Indexes Atomic Updates Map Reduce Access Patterns ? Read / Write Ratio Types of updates Types of queries Considerations No Joins Single Document Transactions only
  • 12. Design Session Use Rich Design Documents post = {author: “kyle”, date: new Date(), text: “my blog post...”, tags: [“mongodb”, “intro”]} >db.post.save(post)
  • 13. >db.posts.find() { _id : ObjectId("4c4ba5c0672c685e5e8aabf3"), author : "kyle", date : "Sat Jul 24 2010 19:47:11 GMT-0700 (PDT)", text : "My first blog", tags : [ "mongodb", "intro" ] } Notes: - ID is unique, but can be anything you’d like
  • 14. Secondary index for “author” // 1 means ascending, -1 means descending >db.posts.ensureIndex({author: 1}) >db.posts.find({author: 'kyle'}) { _id : ObjectId("4c4ba5c0672c685e5e8aabf3"), author : "kyle", ... }
  • 15. Verifying indexes exist >db.system.indexes.find() // Index on ID { name : "_id_", ns : "test.posts", key : { "_id" : 1 } }
  • 16. Verifying indexes exist >db.system.indexes.find() // Index on ID { name : "_id_", ns : "test.posts", key : { "_id" : 1 } } // Index on author { _id : ObjectId("4c4ba6c5672c685e5e8aabf4"), ns : "test.posts", key : { "author" : 1 }, name : "author_1" }
  • 17. Query operators Conditional operators: $ne, $in, $nin, $mod, $all, $size, $exists, $type, .. $lt, $lte, $gt, $gte, $ne, // find posts with any tags >db.posts.find({tags: {$exists: true}})
  • 18. Query operators Conditional operators: $ne, $in, $nin, $mod, $all, $size, $exists, $type, .. $lt, $lte, $gt, $gte, $ne, // find posts with any tags >db.posts.find({tags: {$exists: true}}) Regular expressions: // posts where author starts with k >db.posts.find({author: /^k*/i })
  • 19. Query operators Conditional operators: $ne, $in, $nin, $mod, $all, $size, $exists, $type, .. $lt, $lte, $gt, $gte, $ne, // find posts with any tags >db.posts.find({tags: {$exists: true}}) Regular expressions: // posts where author starts with k >db.posts.find({author: /^k*/i }) Counting: // posts written by mike >db.posts.find({author: “mike”}).count()
  • 20. Extending the Schema comment = {author: “fred”, date: new Date(), text: “super duper”} update = { ‘$push’: {comments: comment}, ‘$inc’: {comments_count: 1}} >db.posts.update({_id: “...” }, update)
  • 21. { _id : ObjectId("4c4ba5c0672c685e5e8aabf3"), author : "kyle", date : "Sat Jul 24 2010 19:47:11 GMT-0700 (PDT)", text : "My first blog", tags : [ "mongodb", "intro" ], comments_count: 1, comments : [ { author : "Fred", date : "Sat Jul 24 2010 20:51:03 GMT-0700 (PDT)", text : "Super Duper" } ]}
  • 22. // create index on nested documents: >db.posts.ensureIndex({"comments.author": 1}) >db.posts.find({comments.author:”Fred”})
  • 23. // create index on nested documents: >db.posts.ensureIndex({"comments.author": 1}) >db.posts.find({comments.author:”kyle”}) // find last 5 posts: >db.posts.find().sort({date:-1}).limit(5)
  • 24. // create index on nested documents: >db.posts.ensureIndex({"comments.author": 1}) >db.posts.find({comments.author:”kyle”}) // find last 5 posts: >db.posts.find().sort({date:-1}).limit(5) // most commented post: >db.posts.find().sort({comments_count:-1}).limit(1) When sorting, check if you need an index
  • 25. Map Reduce Aggregation and batch manipulation Collection in, Collection out Parallel in sharded environments
  • 26. Map reduce mapFunc = function () { this.tags.forEach(function (z) {emit(z, {count:1});}); } reduceFunc = function (k, v) { var total = 0; for (var i = 0; i < v.length; i++) { total += v[i].count; } return {count:total}; } res = db.posts.mapReduce(mapFunc, reduceFunc) >db[res.result].find() { _id : "intro", value : { count : 1 } } { _id : "mongodb", value : { count : 1 } }
  • 27. Review So Far: - Started out with a simple schema - Queried Data - Evolved the schema - Queried / Updated the data some more
  • 28. Wordnik 9B records, 100M queries / week, 1,2TB { entry : { header: { id: 0, headword: "m", sourceDictionary: "GCide", textProns : [ {text: "(em)", seq:0} ], syllables: [ {id: 0, text: "m"} ], sourceDictionary: "1913 Webster", headWord: "m", id: 1, definitions: : [ {text: "M, the thirteenth letter..."}, {text: "As a numeral, M stands for 1000"}] } } }
  • 29. Review So Far: - Started out with a simple schema - Queried Data - Evolved the schema - Queried / Updated the data some more Observations: - Using Rich Documents works well - Simplify relations by embedding them - Iterative development is easy with MongoDB
  • 31. Single Table Inheritance >db.shapes.find() { _id: ObjectId("..."), type: "circle", area: 3.14, radius: 1} { _id: ObjectId("..."), type: "square", area: 4, d: 2} { _id: ObjectId("..."), type: "rect", area: 10, length: 5, width: 2} // find shapes where radius > 0 >db.shapes.find({radius: {$gt: 0}}) // create index >db.shapes.ensureIndex({radius: 1})
  • 32. One to Many - Embedded Array / Array Keys - slice operator to return subset of array - hard to find latest comments across all documents
  • 33. One to Many - Embedded Array / Array Keys - slice operator to return subset of array - hard to find latest comments across all documents - Embedded tree - Single document - Natural - Hard to query
  • 34. One to Many - Embedded Array / Array Keys - slice operator to return subset of array - hard to find latest comments across all documents - Embedded tree - Single document - Natural - Hard to query - Normalized (2 collections) - most flexible - more queries
  • 35. Many - Many Example: - Product can be in many categories - Category can have many products Products id | product_id | category_id Category
  • 36. products: { _id: ObjectId("4c4ca23933fb5941681b912e"), name: "Sumatra Dark Roast", category_ids: [ ObjectId("4c4ca25433fb5941681b912f"), ObjectId("4c4ca25433fb5941681b92af”]}
  • 37. products: { _id: ObjectId("4c4ca23933fb5941681b912e"), name: "Sumatra Dark Roast", category_ids: [ ObjectId("4c4ca25433fb5941681b912f"), ObjectId("4c4ca25433fb5941681b92af”]} categories: { _id: ObjectId("4c4ca25433fb5941681b912f"), name: "Indonesia", product_ids: [ ObjectId("4c4ca23933fb5941681b912e"), ObjectId("4c4ca30433fb5941681b9130"), ObjectId("4c4ca30433fb5941681b913a"]}
  • 38. products: { _id: ObjectId("4c4ca23933fb5941681b912e"), name: "Sumatra Dark Roast", category_ids: [ ObjectId("4c4ca25433fb5941681b912f"), ObjectId("4c4ca25433fb5941681b92af”]} categories: { _id: ObjectId("4c4ca25433fb5941681b912f"), name: "Indonesia", product_ids: [ ObjectId("4c4ca23933fb5941681b912e"), ObjectId("4c4ca30433fb5941681b9130"), ObjectId("4c4ca30433fb5941681b913a"]} //All categories for a given product >db.categories.find({product_ids: ObjectId("4c4ca23933fb5941681b912e")})
  • 39. products: { _id: ObjectId("4c4ca23933fb5941681b912e"), name: "Sumatra Dark Roast", category_ids: [ ObjectId("4c4ca25433fb5941681b912f"), ObjectId("4c4ca25433fb5941681b92af”]} categories: { _id: ObjectId("4c4ca25433fb5941681b912f"), name: "Indonesia", product_ids: [ ObjectId("4c4ca23933fb5941681b912e"), ObjectId("4c4ca30433fb5941681b9130"), ObjectId("4c4ca30433fb5941681b913a"]} //All categories for a given product >db.categories.find({product_ids: ObjectId("4c4ca23933fb5941681b912e")}) //All products for a given category >db.products.find({category_ids: ObjectId("4c4ca25433fb5941681b912f")})
  • 40. Alternative products: { _id: ObjectId("4c4ca23933fb5941681b912e"), name: "Sumatra Dark Roast", category_ids: [ ObjectId("4c4ca25433fb5941681b912f"), ObjectId("4c4ca25433fb5941681b92af”]} categories: { _id: ObjectId("4c4ca25433fb5941681b912f"), name: "Indonesia"}
  • 41. Alternative products: { _id: ObjectId("4c4ca23933fb5941681b912e"), name: "Sumatra Dark Roast", category_ids: [ ObjectId("4c4ca25433fb5941681b912f"), ObjectId("4c4ca25433fb5941681b92af”]} categories: { _id: ObjectId("4c4ca25433fb5941681b912f"), name: "Indonesia"} // All products for a given category >db.products.find({category_ids: ObjectId("4c4ca25433fb5941681b912f")})
  • 42. Alternative products: { _id: ObjectId("4c4ca23933fb5941681b912e"), name: "Sumatra Dark Roast", category_ids: [ ObjectId("4c4ca25433fb5941681b912f"), ObjectId("4c4ca25433fb5941681b92af”]} categories: { _id: ObjectId("4c4ca25433fb5941681b912f"), name: "Indonesia"} // All products for a given category >db.products.find({category_ids: ObjectId("4c4ca25433fb5941681b912f")}) // All categories for a given product product = db.products.find(_id : some_id) >db.categories.find({_id : {$in : product.category_ids}})
  • 43. Trees Full Tree in Document { comments: [ { author: “rpb”, text: “...”, replies: [ {author: “Fred”, text: “...”, replies: []} ]} ]} Pros: Single Document, Performance, Intuitive Cons: Hard to search, Partial Results, 4MB limit
  • 44. Trees Parent Links - Each node is stored as a document - Contains the id of the parent Child Links - Each node contains the id’s of the children - Can support graphs (multiple parents / child)
  • 45. Array of Ancestors - Store Ancestors of a node { _id: "a" } { _id: "b", ancestors: [ "a" ], parent: "a" } { _id: "c", ancestors: [ "a", "b" ], parent: "b" } { _id: "d", ancestors: [ "a", "b" ], parent: "b" } { _id: "e", ancestors: [ "a" ], parent: "a" } { _id: "f", ancestors: [ "a", "e" ], parent: "e" } { _id: "g", ancestors: [ "a", "b", "d" ], parent: "d" }
  • 46. Array of Ancestors - Store Ancestors of a node { _id: "a" } { _id: "b", ancestors: [ "a" ], parent: "a" } { _id: "c", ancestors: [ "a", "b" ], parent: "b" } { _id: "d", ancestors: [ "a", "b" ], parent: "b" } { _id: "e", ancestors: [ "a" ], parent: "a" } { _id: "f", ancestors: [ "a", "e" ], parent: "e" } { _id: "g", ancestors: [ "a", "b", "d" ], parent: "d" } //find all descendants of b: >db.tree2.find({ancestors: ‘b’})
  • 47. Array of Ancestors - Store Ancestors of a node { _id: "a" } { _id: "b", ancestors: [ "a" ], parent: "a" } { _id: "c", ancestors: [ "a", "b" ], parent: "b" } { _id: "d", ancestors: [ "a", "b" ], parent: "b" } { _id: "e", ancestors: [ "a" ], parent: "a" } { _id: "f", ancestors: [ "a", "e" ], parent: "e" } { _id: "g", ancestors: [ "a", "b", "d" ], parent: "d" } //find all descendants of b: >db.tree2.find({ancestors: ‘b’}) //find all ancestors of f: >ancestors = db.tree2.findOne({_id:’f’}).ancestors >db.tree2.find({_id: { $in : ancestors})
  • 48. findAndModify Queue example //Example: grab highest priority job and mark job = db.jobs.findAndModify({ query: {inprogress: false}, sort: {priority: -1), update: {$set: {inprogress: true, started: new Date()}}, new: true})
  • 49. More Cool Stuff • Aggregation • Capped collections • GridFS • Geo
  • 50. Learn More Kyle’s presentation + video: http://www.slideshare.net/kbanker/mongodb-schema-design http://www.blip.tv/file/3704083 Dwight’s presentation http://www.slideshare.net/mongosf/schema-design-with-mongodb-dwight- merriman Documentation Trees: http://www.mongodb.org/display/DOCS/Trees+in+MongoDB Queues: http://www.mongodb.org/display/DOCS/findandmodify+Command Aggregration: http://www.mongodb.org/display/DOCS/Aggregation Capped Col. : http://www.mongodb.org/display/DOCS/Capped+Collections Geo: http://www.mongodb.org/display/DOCS/Geospatial+Indexing GridFS: http://www.mongodb.org/display/DOCS/GridFS+Specification
  • 52. Download MongoDB and let us know what you think @mongodb http://www.mongodb.org
  • 53. DBRef DBRef {$ref: collection, $id: id_value} - Think URL - YDSMV: your driver support may vary Sample Schema: nr = {note_refs: [{"$ref" : "notes", "$id" : 5}, ... ]} Dereferencing: nr.forEach(function(r) { printjson(db[r.$ref].findOne({_id: r.$id})); }
  • 54. BSON Mongodb stores data in BSON internally Lightweight, Traversable, Efficient encoding Typed boolean, integer, float, date, string, binary, array...

Editor's Notes

  1. blog post twitter