SlideShare a Scribd company logo
1 of 81
Mongo or Die!
How MongoDB powers Doodle or Die




        Aaron Silverman
             (@Zugwalt)
Doodle or Die




@DoodleOrDie
What is Doodle or Die?
Telephone
Phrase     I'd like some beer!

Phrase     I'd like some deer

Phrase       I see no deer

Phrase        I’ve no idea!
Doodle or Die

Doodle


Phrase         Shining Apple


Doodle

Phrase      Eat your fruit or DIE!
What Powers Doodle or Die?
Started very, very small


            4 Cores
          128MB RAM
            Node Server

           MongoDB Server
Got serious about our servers

                     Small - 2GB

     8 Cores      MongoDB Server
   256MB RAM
    Node Server
Called in some Reinforcements


                      Large - 5GB

    12 Cores        MongoDB Server
    1GB RAM
     Node Server
In the last 30 Days:

• 2,500,000 page views

• 100,000 uniques

• 35,000 active player accounts

• 2,000,000 new doodles and descriptions
“Small Data”
Mongo DB           • Player Info
                   • Chain Info (excluding
4 GB data size
                     doodles)
<1 GB index size   • Group Info
~10 queries/sec    • Game State
                   • Logs
Amazon
170 GB data size   • Doodles
                   • Static Content
8 GB in/month      • Compressed
200 GB out/month     Database Backups
MongoDB - $65 / month




Daily backups to Amazon S3: $16/mo
Amazon S3 - $70 / month
Node - $62/ month
Total Cost To Host: $197/month
     MongoDB     $65
     Amazon S3   $70
     Node        $62
     Total       $197
PAAS Provides Easy Upgrade Path
General Principles
Custom _id
Partially random string generated using
ShortId node module
                        ObjectId
        ObjectId("4fd02d5d78315a502d15cdde")
        ObjectId("4fd02d5a78315a502d15cddd")
        ObjectId("4fd02d5878315a502d15cddc")

                      ShortId
                "8rOIwh2VD"
                "1qyY61Lu1"
                "5GQnbx-1"
• Shorter, less cumbersome in code and
  queries
db.players.findOne({_id: ‘58mwYlTKV’});

db.chains.update({_id: ‘58mwYlTKV’},
          {$set: activePlayer_id: ‘88ueYaL6V’});

• Randomness could help with sharding;
  more importantly makes it harder to
  cheat
http://doodleordie.com/c/5ONtvvSGH


<span class="doodle" data-jsonp="http://doodles.s3.amazonaws.com/d2/Eh8-
Po2R5/1Em5kj3LY.js">
Question Oriented Subdocuments

  What chain is this player working on right now?




  What are this player’s stats?




  Which players are not eligible to be assigned this chain?
Goal is for most “Questions” to be able to
be answered in one query from one sub
document

db.players.findOne({_id: ‘58mwYlTKV’},
             {‘game.recentSkips’: 1});



Related “Questions” will share common
ancestors

db.players.findOne({_id: ‘58mwYlTKV’},
             {game: 1});
Indexes are designed to make answering
questions easy!

Which player is working on this chain?
db.players.ensureIndex({‘game.activeChain_id’: 1});




What chains are recently awaiting a new doodle?

 db.chains.ensureIndex({inUse: -1,
              activeState: 1
              lastModified" : -1});
Doodle or Die Collections
Disclaimer: Much of the original Doodle or
Die code and schema were created during a
weekend long hackathon!
players


Primary   chains

          groups

          sessions
Support
            log
Players
players
  game            Often


chainHistory

   stats         Query
               Frequency
  account
   login
                  Rarely
    info
players
        game               •   activeState
                           •   activeChain_id
     chainHistory          •   activeStepIndex
                           •   recentSkips
         stats
       account

Answerslogin    question:
“What is this player working on right now?”
                info
 db.players.findOne({_id: ‘58mwYlTKV’}, {game: 1});
players                             Chain1
            game                            • datePlayed
                                            • dateViewed
       chainHistory

              stats
           account                                    ChainN

      login
Answers the question:
“What has the player worked on?”
       info
db.players.findOne({_id: ‘58mwYlTKV’}, {chainHistory: 1});
players               Chain1
       game              • datePlayed
                         • dateViewed
    chainHistory

        stats
      account                  ChainN

YUCK!   login
Plan to refactor out along with a refactor of
         info
how chains store steps
players                            •       totalSteps
           game                               •       drawSteps
                                              •       phraseSteps
      chainHistory                            •       numSkips
                                              •       numLikes
             stats
          account
      login
Answers the question:
“How active/good is this player?”
       info
db.players.findOne({_id: ‘58mwYlTKV’}, {stats: 1});
Chains
chains
•   activePlayer_id
•   activeState
•   numSteps
•   lastModified
       ineligiblePlayer_ids
                      steps
chains are assigned (not as many questions)
db.chains.findOne({inUse: false,
            activeState : player.game.activeState,
            ineligiblePlayer_ids: {$ne: player._id},
            lastModified: { $gte: timeRange}});
chains           [player_id1
                            player_id2,
•   activePlayer_id         player_id3
•   activeState                   …
•   numSteps                player_idN]
•   lastModified

              *
    ineligiblePlayer_ids

Note: $addToSet and $pull work great in
          steps
maintaining this array
chains           [

•   activePlayer_id               Step1
•   activeState                • player_id
•   numSteps                   • state
•   lastModified               • date
                                 content
              *
    ineligiblePlayer_ids
                                  StepN
           steps
                           ]
Description Step Content:
  • phrase



Doodle Step Content:
  •   url (points to S3)
  •   time
  •   numStrokes
  •   numDistinctColors
Description Step Content:
  • phrase



Doodle Step Content:
  •   url (points to S3)
  •   time
  •   numStrokes
  •   numDistinctColors
We plan to stop embedding steps in chains,
and link to “doodles” and “descriptions”
collections
          doodles             descriptions
  •   player_id               • player_id
  •   date                    • date
  •   url (points to S3)      • text
  •   time
  •   numStrokes
  •   numDistinctColors
How Does it all Work?
players queried for users who are associated
with the authenticated twitter account

db.players.find({‘login.twitter.uid’: ‘XXXXXXX’},
                      {game: 1, chainHistory: 1});




chain history used to load thumbnails,
previous chain is loaded

db.chains.find({_id: {$in: [player.game.activeChain_id,
                  player.game.lastChain_id]}});
chains collection searched and atomically
updated for unclaimed eligible chain to be
given to player

 db.chains.findAndModify(
            {inUse: false,
             activeState : player.game.activeState,
             ineligiblePlayer_ids: {$ne: player._id},
             lastModified: { $gte: timeRange}},
            {$set: {inUse: true,
                   activePlayer_id: player._id,
             $addToSet:
                {ineligiblePlayer_ids: player._id}});
Content saved to chain

db.chains.update({_id: chain._id,
           activePlayer_id: player._id}},
          {$inc: {numSteps: 1},
           $set: inUse: false,
               lastModified: datePlayed}
           $unset: {activePlayer_id: 1},
           $push: {steps: {
                   player_id: player._id,
                   state: chain.activeState,
                   content: content,
                   date: datePlayed}}});
Doodle strokes will be saved to S3
(but url to S3 and metadata saved to chain)
{"color":"#000000","size":15,"path":[307,66,308,66,308,68,308,69,308,70,308,71,308,7
2,308,73,306,76,305,79,305,81,302,83,302,84,302,85,302,86,301,87,300,89,300,90,300
,91,300,92,300,95,300,97,300,102,300,103,300,104,300,108,300,109,300,110,301,114,
303,116,304,116,305,119,305,121,307,124,309,127,310,130,310,131,313,132,314,133,
316,137,317,138,320,140,321,140,323,143,326,143,328,143,333,144,337,144,341,144,
343,144,347,143,352,143,354,141,357,140,358,140,359,139,362,138,363,138,365,137,
368,135,369,132,370,131,371,130,374,128,375,128,376,125,378,125,379,124,380,123,
381,123,382,120,385,119,386,118,388,115,391,112,394,109,394,107,394,106,397,104,
397,103,397,102,397,101,397,100,397,98,397,96,397,94,397,93,397,91,397,90,397,88,
397,87,397,86,397,83,395,80,395,79,395,77,394,74,393,72,393,70,393,67,392,65,391,6
3,389,62,388,59,386,57,383,54,383,52,381,49,379,48,378,47,376,46,375,44,374,43,372
,43,370,42,369,42,368,42,364,41,362,41,359,41,355,41,351,42,349,42,347,42,346,44,3
43,44,342,45,339,46,337,47,336,48,333,49,332,51,330,51,328,51,327,52,326,53,323,53
,322,53,321,54,320,55,317,55,316,56,314,58,309,59,306,61,306,62,305,62,304,63]}
Player’s chainHistory retrieved
db.players.find({‘login.urlSafe’: urlSafeUid},
          {chainHistory: 1});




chainHistory filtered and sorted on
server, Applicable chains/steps retrieved
db.chains.find({$in: chain_idArr});




Retrieved chains ordered (on server) based
on previously sorted chainHistory
Stats are loaded from the counting log which
is essentially a bunch of counters
incremented

db.log.find({_id: {$in: [‘2012-06-20’, ‘2012-06-20’,
‘2012-06-20’, ‘2012-06-20’]}});




Extremely simple implementation using
nested subdocuments for organization
Some Additional Doodle or Die Tricks
Build assumptions into queries
Alice and Bob are in an awesome group

groups:
{
  _id: ‘8rOIwh2VD’,
  members: [
     {name: ‘Alice’, dateJoined: ‘2012-05-24’},
     {name: ‘Bob’, dateJoined: ‘2012-05-25’}
  ]
  banned: [
     {name: ‘Eve’, dateBanned: ‘2012-05-25’}
    ]
}




Eve tries to join despite being banned!
Bugs in our code fail to detect Eve’s trickery
and the update query is run!

groups.update(
  {_id: ‘8rOIwh2VD’},
  {$push:
    {members:
      {name: ‘Eve’,
       dateJoined: new Date()}
      },
  },
  function(err) {
          if (err) throw err;
          callback();
  });
groups:
{
  _id: ‘8rOIwh2VD’,
  members: [
     {name: ‘Alice’, dateJoined: ‘2012-05-24’},
     {name: ‘Bob’, dateJoined: ‘2012-05-25’},
     {name: ‘Eve’, dateJoined: ‘2012-05-26’}
  ]
  banned: [
     {name: ‘Eve’, dateRequested: ‘2012-05-25’}
    ]
}




Blast! Eve got through! How can we help
prevent this?
Bake in our assumptions!

groups.update(
  {_id: ‘8rOIwh2VD’,
   ‘members.name’: {$ne: ‘Eve’},
   ‘banned.name’: {$ne: ‘Eve’}},
  {$push:
    {members:
      {name: ‘Eve’,
       dateJoined: new Date()}
        },
  },
  function(err, updateCount) {
      if (err) throw err;
      if (updateCount !== 1) throw new Error(‘bugs!’);
      callback(updateCount === 1);
  });
Always Specify Fields
To assign a player a new chain, we only need
their _id and game information

                   players

                    game
                 chainHistory
                    stats
                   account
                    login
                     info
To load a player’s profile content, we just
need their history, stats, and profile info

                   players

                   game
                chainHistory
                    stats
                  account
                    login
                    info
We need to assign Bob a new chain, lets
figure out what state he needs next

db.players.find({name: ‘Bob’});




This will fetch and send back the ENTIRE
player object!
Lets specify that we only want our “game”
subdocument
db.players.find({name: ‘Bob’}, {fields: [‘game’]});




Hooray! Much less to retrieve and send
over the series of tubes.
Store Everything!
If you have information available, save it
even if you don’t plan on using it!

db.chains.update({_id: ‘2VmVO18hs’},
          {$push: {player_id: ‘1qyY61Lu1’,
               state: ‘draw’,
               date: new Date(),
               content: {time: 106896,
                                 count: 27,
                                 width: 520,
                                 height: 390,
                                 step_id: ‘1i7RlFbgU’
                      }
          });
Some Pain Points
Less obvious database structure


mysql> DESC players;
+----------------+---------+------+-----+---------+-------+
| Field         | Type | Null | Key | Default | Extra |
+----------------+---------+------+-----+---------+-------+
| id          | int(11) | NO | PRI | NULL |             |
| activeStateId | int(11) | YES | | NULL |                  |
| activeStepId | int(11) | YES | | NULL |                   |
+----------------+---------+------+-----+---------+-------+
Data integrity up to application


Mysql> ALTER TABLE players
    ADD CONSTRAINT fk_players_chains
     FOREIGN KEY (activeChainId) REFERENCES chains(id);




/* Oh no! This is going to mess things up! */

players.update({_id: ‘c58D4’},
         {$set: {‘game.activeChain_id’: ‘bad_id’}});
No mature GUI query development tools
If we could start over would we still use MongoDB?
Absolutely!
• NoSQL in general is great for rapid prototyping

• Fantastic performance

• Intuitive language keeps it easy to run one-off
  queries / refactor schema

• Excellent (and now officially supported) Node
  driver
Questions?




@Zugwalt     @DoodleOrDie

More Related Content

What's hot

The Ring programming language version 1.7 book - Part 196 of 196
The Ring programming language version 1.7 book - Part 196 of 196The Ring programming language version 1.7 book - Part 196 of 196
The Ring programming language version 1.7 book - Part 196 of 196Mahmoud Samir Fayed
 
The Ring programming language version 1.2 book - Part 82 of 84
The Ring programming language version 1.2 book - Part 82 of 84The Ring programming language version 1.2 book - Part 82 of 84
The Ring programming language version 1.2 book - Part 82 of 84Mahmoud Samir Fayed
 
The Ring programming language version 1.2 book - Part 83 of 84
The Ring programming language version 1.2 book - Part 83 of 84The Ring programming language version 1.2 book - Part 83 of 84
The Ring programming language version 1.2 book - Part 83 of 84Mahmoud Samir Fayed
 
The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!Donny Wals
 
2018 PyCon Korea - Ring
2018 PyCon Korea - Ring2018 PyCon Korea - Ring
2018 PyCon Korea - RingYunWon Jeong
 
ZaCon 4 (2012) - Game Hacking
ZaCon 4 (2012) - Game HackingZaCon 4 (2012) - Game Hacking
ZaCon 4 (2012) - Game HackingHypnZA
 
CouchDB @ red dirt ruby conference
CouchDB @ red dirt ruby conferenceCouchDB @ red dirt ruby conference
CouchDB @ red dirt ruby conferenceleinweber
 
MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...
MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...
MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...MongoDB
 
MongoDB @ Frankfurt NoSql User Group
MongoDB @  Frankfurt NoSql User GroupMongoDB @  Frankfurt NoSql User Group
MongoDB @ Frankfurt NoSql User GroupChris Harris
 
Optimizing Slow Queries with Indexes and Creativity
Optimizing Slow Queries with Indexes and CreativityOptimizing Slow Queries with Indexes and Creativity
Optimizing Slow Queries with Indexes and CreativityMongoDB
 
Jan Lehnardt Couch Db In A Real World Setting
Jan Lehnardt Couch Db In A Real World SettingJan Lehnardt Couch Db In A Real World Setting
Jan Lehnardt Couch Db In A Real World SettingGeorge Ang
 
How Signpost uses MongoDB for Tracking and Analytics
How Signpost uses MongoDB for Tracking and AnalyticsHow Signpost uses MongoDB for Tracking and Analytics
How Signpost uses MongoDB for Tracking and Analyticsmattinsler
 
Back to Basics: My First MongoDB Application
Back to Basics: My First MongoDB ApplicationBack to Basics: My First MongoDB Application
Back to Basics: My First MongoDB ApplicationMongoDB
 
DEF CON 23 - amit ashbel and maty siman - game of hacks
DEF CON 23 - amit ashbel and maty siman - game of hacks DEF CON 23 - amit ashbel and maty siman - game of hacks
DEF CON 23 - amit ashbel and maty siman - game of hacks Felipe Prado
 
ココロもつながるオンラインゲーム–アットゲームズ–のMongoDB導入事例
ココロもつながるオンラインゲーム–アットゲームズ–のMongoDB導入事例ココロもつながるオンラインゲーム–アットゲームズ–のMongoDB導入事例
ココロもつながるオンラインゲーム–アットゲームズ–のMongoDB導入事例Naoki Sega
 
MySQLでNoSQL - アメーバピグでのNoSQLの実例
MySQLでNoSQL - アメーバピグでのNoSQLの実例MySQLでNoSQL - アメーバピグでのNoSQLの実例
MySQLでNoSQL - アメーバピグでのNoSQLの実例Kazuhiro Oinuma
 
Game of Fraud Detection with SQL and Machine Learning
Game of Fraud Detection with SQL and Machine LearningGame of Fraud Detection with SQL and Machine Learning
Game of Fraud Detection with SQL and Machine LearningChris Saxon
 
MongoD Essentials
MongoD EssentialsMongoD Essentials
MongoD Essentialszahid-mian
 

What's hot (20)

The Ring programming language version 1.7 book - Part 196 of 196
The Ring programming language version 1.7 book - Part 196 of 196The Ring programming language version 1.7 book - Part 196 of 196
The Ring programming language version 1.7 book - Part 196 of 196
 
The Ring programming language version 1.2 book - Part 82 of 84
The Ring programming language version 1.2 book - Part 82 of 84The Ring programming language version 1.2 book - Part 82 of 84
The Ring programming language version 1.2 book - Part 82 of 84
 
The Ring programming language version 1.2 book - Part 83 of 84
The Ring programming language version 1.2 book - Part 83 of 84The Ring programming language version 1.2 book - Part 83 of 84
The Ring programming language version 1.2 book - Part 83 of 84
 
The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!
 
MySQL Rises with JSON Support
MySQL Rises with JSON SupportMySQL Rises with JSON Support
MySQL Rises with JSON Support
 
2018 PyCon Korea - Ring
2018 PyCon Korea - Ring2018 PyCon Korea - Ring
2018 PyCon Korea - Ring
 
ZaCon 4 (2012) - Game Hacking
ZaCon 4 (2012) - Game HackingZaCon 4 (2012) - Game Hacking
ZaCon 4 (2012) - Game Hacking
 
CouchDB @ red dirt ruby conference
CouchDB @ red dirt ruby conferenceCouchDB @ red dirt ruby conference
CouchDB @ red dirt ruby conference
 
MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...
MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...
MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...
 
MongoDB @ Frankfurt NoSql User Group
MongoDB @  Frankfurt NoSql User GroupMongoDB @  Frankfurt NoSql User Group
MongoDB @ Frankfurt NoSql User Group
 
Optimizing Slow Queries with Indexes and Creativity
Optimizing Slow Queries with Indexes and CreativityOptimizing Slow Queries with Indexes and Creativity
Optimizing Slow Queries with Indexes and Creativity
 
Jan Lehnardt Couch Db In A Real World Setting
Jan Lehnardt Couch Db In A Real World SettingJan Lehnardt Couch Db In A Real World Setting
Jan Lehnardt Couch Db In A Real World Setting
 
How Signpost uses MongoDB for Tracking and Analytics
How Signpost uses MongoDB for Tracking and AnalyticsHow Signpost uses MongoDB for Tracking and Analytics
How Signpost uses MongoDB for Tracking and Analytics
 
Back to Basics: My First MongoDB Application
Back to Basics: My First MongoDB ApplicationBack to Basics: My First MongoDB Application
Back to Basics: My First MongoDB Application
 
Letgo Data Platform: A global overview
Letgo Data Platform: A global overviewLetgo Data Platform: A global overview
Letgo Data Platform: A global overview
 
DEF CON 23 - amit ashbel and maty siman - game of hacks
DEF CON 23 - amit ashbel and maty siman - game of hacks DEF CON 23 - amit ashbel and maty siman - game of hacks
DEF CON 23 - amit ashbel and maty siman - game of hacks
 
ココロもつながるオンラインゲーム–アットゲームズ–のMongoDB導入事例
ココロもつながるオンラインゲーム–アットゲームズ–のMongoDB導入事例ココロもつながるオンラインゲーム–アットゲームズ–のMongoDB導入事例
ココロもつながるオンラインゲーム–アットゲームズ–のMongoDB導入事例
 
MySQLでNoSQL - アメーバピグでのNoSQLの実例
MySQLでNoSQL - アメーバピグでのNoSQLの実例MySQLでNoSQL - アメーバピグでのNoSQLの実例
MySQLでNoSQL - アメーバピグでのNoSQLの実例
 
Game of Fraud Detection with SQL and Machine Learning
Game of Fraud Detection with SQL and Machine LearningGame of Fraud Detection with SQL and Machine Learning
Game of Fraud Detection with SQL and Machine Learning
 
MongoD Essentials
MongoD EssentialsMongoD Essentials
MongoD Essentials
 

Similar to Mongo or Die: How MongoDB Powers Doodle or Die

Mongodb index 讀書心得
Mongodb index 讀書心得Mongodb index 讀書心得
Mongodb index 讀書心得cc liu
 
PostgreSQLからMongoDBへ
PostgreSQLからMongoDBへPostgreSQLからMongoDBへ
PostgreSQLからMongoDBへBasuke Suzuki
 
Kicking ass with redis
Kicking ass with redisKicking ass with redis
Kicking ass with redisDvir Volk
 
Boardgamegeek scraping
Boardgamegeek scrapingBoardgamegeek scraping
Boardgamegeek scrapingegoodwintx
 
MongoDB Performance Tuning
MongoDB Performance TuningMongoDB Performance Tuning
MongoDB Performance TuningPuneet Behl
 
Basic Multiplayer Online Game with Node.js & dgt-net
Basic Multiplayer Online Game with Node.js & dgt-netBasic Multiplayer Online Game with Node.js & dgt-net
Basic Multiplayer Online Game with Node.js & dgt-netPisit Tangkoblarp
 
Tips and Tricks for Avoiding Common Query Pitfalls Christian Kurze
Tips and Tricks for Avoiding Common Query Pitfalls Christian KurzeTips and Tricks for Avoiding Common Query Pitfalls Christian Kurze
Tips and Tricks for Avoiding Common Query Pitfalls Christian KurzeMongoDB
 
My 10 days with Phaser.js - WarsawJS Meetup #13
My 10 days with Phaser.js - WarsawJS Meetup #13My 10 days with Phaser.js - WarsawJS Meetup #13
My 10 days with Phaser.js - WarsawJS Meetup #13Piotr Kowalski
 
MongoDB World 2018: Tips and Tricks for Avoiding Common Query Pitfalls
MongoDB World 2018: Tips and Tricks for Avoiding Common Query PitfallsMongoDB World 2018: Tips and Tricks for Avoiding Common Query Pitfalls
MongoDB World 2018: Tips and Tricks for Avoiding Common Query PitfallsMongoDB
 
Advanced data modeling with apache cassandra
Advanced data modeling with apache cassandraAdvanced data modeling with apache cassandra
Advanced data modeling with apache cassandraPatrick McFadin
 
Facebook Sentiment Analysis - What is Facebook Saying about Nintendo?
Facebook Sentiment Analysis - What is Facebook Saying about Nintendo?Facebook Sentiment Analysis - What is Facebook Saying about Nintendo?
Facebook Sentiment Analysis - What is Facebook Saying about Nintendo?Gregory Zapata
 
MongoDB: Optimising for Performance, Scale & Analytics
MongoDB: Optimising for Performance, Scale & AnalyticsMongoDB: Optimising for Performance, Scale & Analytics
MongoDB: Optimising for Performance, Scale & AnalyticsServer Density
 
Understanding and improving games through machine learning - Natasha Latysheva
Understanding and improving games through machine learning - Natasha LatyshevaUnderstanding and improving games through machine learning - Natasha Latysheva
Understanding and improving games through machine learning - Natasha LatyshevaLauren Cormack
 
MongoDB for Time Series Data Part 3: Sharding
MongoDB for Time Series Data Part 3: ShardingMongoDB for Time Series Data Part 3: Sharding
MongoDB for Time Series Data Part 3: ShardingMongoDB
 
Database madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyDatabase madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyJaime Buelta
 
2011/10/08_Playframework_GAE_to_Heroku
2011/10/08_Playframework_GAE_to_Heroku2011/10/08_Playframework_GAE_to_Heroku
2011/10/08_Playframework_GAE_to_HerokuTakeshi Hagikura
 
Cache on Delivery
Cache on DeliveryCache on Delivery
Cache on DeliverySensePost
 
Ensuring High Availability for Real-time Analytics featuring Boxed Ice / Serv...
Ensuring High Availability for Real-time Analytics featuring Boxed Ice / Serv...Ensuring High Availability for Real-time Analytics featuring Boxed Ice / Serv...
Ensuring High Availability for Real-time Analytics featuring Boxed Ice / Serv...MongoDB
 

Similar to Mongo or Die: How MongoDB Powers Doodle or Die (20)

Mongodb index 讀書心得
Mongodb index 讀書心得Mongodb index 讀書心得
Mongodb index 讀書心得
 
PostgreSQLからMongoDBへ
PostgreSQLからMongoDBへPostgreSQLからMongoDBへ
PostgreSQLからMongoDBへ
 
Kicking ass with redis
Kicking ass with redisKicking ass with redis
Kicking ass with redis
 
Boardgamegeek scraping
Boardgamegeek scrapingBoardgamegeek scraping
Boardgamegeek scraping
 
MongoDB Performance Tuning
MongoDB Performance TuningMongoDB Performance Tuning
MongoDB Performance Tuning
 
Basic Multiplayer Online Game with Node.js & dgt-net
Basic Multiplayer Online Game with Node.js & dgt-netBasic Multiplayer Online Game with Node.js & dgt-net
Basic Multiplayer Online Game with Node.js & dgt-net
 
Tips and Tricks for Avoiding Common Query Pitfalls Christian Kurze
Tips and Tricks for Avoiding Common Query Pitfalls Christian KurzeTips and Tricks for Avoiding Common Query Pitfalls Christian Kurze
Tips and Tricks for Avoiding Common Query Pitfalls Christian Kurze
 
My 10 days with Phaser.js - WarsawJS Meetup #13
My 10 days with Phaser.js - WarsawJS Meetup #13My 10 days with Phaser.js - WarsawJS Meetup #13
My 10 days with Phaser.js - WarsawJS Meetup #13
 
MongoDB World 2018: Tips and Tricks for Avoiding Common Query Pitfalls
MongoDB World 2018: Tips and Tricks for Avoiding Common Query PitfallsMongoDB World 2018: Tips and Tricks for Avoiding Common Query Pitfalls
MongoDB World 2018: Tips and Tricks for Avoiding Common Query Pitfalls
 
Advanced data modeling with apache cassandra
Advanced data modeling with apache cassandraAdvanced data modeling with apache cassandra
Advanced data modeling with apache cassandra
 
Facebook Sentiment Analysis - What is Facebook Saying about Nintendo?
Facebook Sentiment Analysis - What is Facebook Saying about Nintendo?Facebook Sentiment Analysis - What is Facebook Saying about Nintendo?
Facebook Sentiment Analysis - What is Facebook Saying about Nintendo?
 
MongoDB: Optimising for Performance, Scale & Analytics
MongoDB: Optimising for Performance, Scale & AnalyticsMongoDB: Optimising for Performance, Scale & Analytics
MongoDB: Optimising for Performance, Scale & Analytics
 
Understanding and improving games through machine learning - Natasha Latysheva
Understanding and improving games through machine learning - Natasha LatyshevaUnderstanding and improving games through machine learning - Natasha Latysheva
Understanding and improving games through machine learning - Natasha Latysheva
 
MongoDB for Time Series Data Part 3: Sharding
MongoDB for Time Series Data Part 3: ShardingMongoDB for Time Series Data Part 3: Sharding
MongoDB for Time Series Data Part 3: Sharding
 
Extjs + Gears
Extjs + GearsExtjs + Gears
Extjs + Gears
 
Database madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyDatabase madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemy
 
Deep Dive on Amazon DynamoDB
Deep Dive on Amazon DynamoDBDeep Dive on Amazon DynamoDB
Deep Dive on Amazon DynamoDB
 
2011/10/08_Playframework_GAE_to_Heroku
2011/10/08_Playframework_GAE_to_Heroku2011/10/08_Playframework_GAE_to_Heroku
2011/10/08_Playframework_GAE_to_Heroku
 
Cache on Delivery
Cache on DeliveryCache on Delivery
Cache on Delivery
 
Ensuring High Availability for Real-time Analytics featuring Boxed Ice / Serv...
Ensuring High Availability for Real-time Analytics featuring Boxed Ice / Serv...Ensuring High Availability for Real-time Analytics featuring Boxed Ice / Serv...
Ensuring High Availability for Real-time Analytics featuring Boxed Ice / Serv...
 

Recently uploaded

SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 

Recently uploaded (20)

SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 

Mongo or Die: How MongoDB Powers Doodle or Die

  • 1. Mongo or Die! How MongoDB powers Doodle or Die Aaron Silverman (@Zugwalt)
  • 3. What is Doodle or Die?
  • 4. Telephone Phrase I'd like some beer! Phrase I'd like some deer Phrase I see no deer Phrase I’ve no idea!
  • 5. Doodle or Die Doodle Phrase Shining Apple Doodle Phrase Eat your fruit or DIE!
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 12.
  • 13. Started very, very small 4 Cores 128MB RAM Node Server MongoDB Server
  • 14. Got serious about our servers Small - 2GB 8 Cores MongoDB Server 256MB RAM Node Server
  • 15. Called in some Reinforcements Large - 5GB 12 Cores MongoDB Server 1GB RAM Node Server
  • 16. In the last 30 Days: • 2,500,000 page views • 100,000 uniques • 35,000 active player accounts • 2,000,000 new doodles and descriptions
  • 17. “Small Data” Mongo DB • Player Info • Chain Info (excluding 4 GB data size doodles) <1 GB index size • Group Info ~10 queries/sec • Game State • Logs Amazon 170 GB data size • Doodles • Static Content 8 GB in/month • Compressed 200 GB out/month Database Backups
  • 18. MongoDB - $65 / month Daily backups to Amazon S3: $16/mo
  • 19. Amazon S3 - $70 / month
  • 20. Node - $62/ month
  • 21. Total Cost To Host: $197/month MongoDB $65 Amazon S3 $70 Node $62 Total $197
  • 22. PAAS Provides Easy Upgrade Path
  • 24. Custom _id Partially random string generated using ShortId node module ObjectId ObjectId("4fd02d5d78315a502d15cdde") ObjectId("4fd02d5a78315a502d15cddd") ObjectId("4fd02d5878315a502d15cddc") ShortId "8rOIwh2VD" "1qyY61Lu1" "5GQnbx-1"
  • 25. • Shorter, less cumbersome in code and queries db.players.findOne({_id: ‘58mwYlTKV’}); db.chains.update({_id: ‘58mwYlTKV’}, {$set: activePlayer_id: ‘88ueYaL6V’}); • Randomness could help with sharding; more importantly makes it harder to cheat http://doodleordie.com/c/5ONtvvSGH <span class="doodle" data-jsonp="http://doodles.s3.amazonaws.com/d2/Eh8- Po2R5/1Em5kj3LY.js">
  • 26. Question Oriented Subdocuments What chain is this player working on right now? What are this player’s stats? Which players are not eligible to be assigned this chain?
  • 27. Goal is for most “Questions” to be able to be answered in one query from one sub document db.players.findOne({_id: ‘58mwYlTKV’}, {‘game.recentSkips’: 1}); Related “Questions” will share common ancestors db.players.findOne({_id: ‘58mwYlTKV’}, {game: 1});
  • 28. Indexes are designed to make answering questions easy! Which player is working on this chain? db.players.ensureIndex({‘game.activeChain_id’: 1}); What chains are recently awaiting a new doodle? db.chains.ensureIndex({inUse: -1, activeState: 1 lastModified" : -1});
  • 29. Doodle or Die Collections
  • 30. Disclaimer: Much of the original Doodle or Die code and schema were created during a weekend long hackathon!
  • 31.
  • 32. players Primary chains groups sessions Support log
  • 34. players game Often chainHistory stats Query Frequency account login Rarely info
  • 35. players game • activeState • activeChain_id chainHistory • activeStepIndex • recentSkips stats account Answerslogin question: “What is this player working on right now?” info db.players.findOne({_id: ‘58mwYlTKV’}, {game: 1});
  • 36. players Chain1 game • datePlayed • dateViewed chainHistory stats account ChainN login Answers the question: “What has the player worked on?” info db.players.findOne({_id: ‘58mwYlTKV’}, {chainHistory: 1});
  • 37. players Chain1 game • datePlayed • dateViewed chainHistory stats account ChainN YUCK! login Plan to refactor out along with a refactor of info how chains store steps
  • 38. players • totalSteps game • drawSteps • phraseSteps chainHistory • numSkips • numLikes stats account login Answers the question: “How active/good is this player?” info db.players.findOne({_id: ‘58mwYlTKV’}, {stats: 1});
  • 40. chains • activePlayer_id • activeState • numSteps • lastModified ineligiblePlayer_ids steps chains are assigned (not as many questions) db.chains.findOne({inUse: false, activeState : player.game.activeState, ineligiblePlayer_ids: {$ne: player._id}, lastModified: { $gte: timeRange}});
  • 41. chains [player_id1 player_id2, • activePlayer_id player_id3 • activeState … • numSteps player_idN] • lastModified * ineligiblePlayer_ids Note: $addToSet and $pull work great in steps maintaining this array
  • 42. chains [ • activePlayer_id Step1 • activeState • player_id • numSteps • state • lastModified • date content * ineligiblePlayer_ids StepN steps ]
  • 43. Description Step Content: • phrase Doodle Step Content: • url (points to S3) • time • numStrokes • numDistinctColors
  • 44. Description Step Content: • phrase Doodle Step Content: • url (points to S3) • time • numStrokes • numDistinctColors
  • 45. We plan to stop embedding steps in chains, and link to “doodles” and “descriptions” collections doodles descriptions • player_id • player_id • date • date • url (points to S3) • text • time • numStrokes • numDistinctColors
  • 46. How Does it all Work?
  • 47.
  • 48. players queried for users who are associated with the authenticated twitter account db.players.find({‘login.twitter.uid’: ‘XXXXXXX’}, {game: 1, chainHistory: 1}); chain history used to load thumbnails, previous chain is loaded db.chains.find({_id: {$in: [player.game.activeChain_id, player.game.lastChain_id]}});
  • 49.
  • 50. chains collection searched and atomically updated for unclaimed eligible chain to be given to player db.chains.findAndModify( {inUse: false, activeState : player.game.activeState, ineligiblePlayer_ids: {$ne: player._id}, lastModified: { $gte: timeRange}}, {$set: {inUse: true, activePlayer_id: player._id, $addToSet: {ineligiblePlayer_ids: player._id}});
  • 51.
  • 52. Content saved to chain db.chains.update({_id: chain._id, activePlayer_id: player._id}}, {$inc: {numSteps: 1}, $set: inUse: false, lastModified: datePlayed} $unset: {activePlayer_id: 1}, $push: {steps: { player_id: player._id, state: chain.activeState, content: content, date: datePlayed}}});
  • 53.
  • 54. Doodle strokes will be saved to S3 (but url to S3 and metadata saved to chain) {"color":"#000000","size":15,"path":[307,66,308,66,308,68,308,69,308,70,308,71,308,7 2,308,73,306,76,305,79,305,81,302,83,302,84,302,85,302,86,301,87,300,89,300,90,300 ,91,300,92,300,95,300,97,300,102,300,103,300,104,300,108,300,109,300,110,301,114, 303,116,304,116,305,119,305,121,307,124,309,127,310,130,310,131,313,132,314,133, 316,137,317,138,320,140,321,140,323,143,326,143,328,143,333,144,337,144,341,144, 343,144,347,143,352,143,354,141,357,140,358,140,359,139,362,138,363,138,365,137, 368,135,369,132,370,131,371,130,374,128,375,128,376,125,378,125,379,124,380,123, 381,123,382,120,385,119,386,118,388,115,391,112,394,109,394,107,394,106,397,104, 397,103,397,102,397,101,397,100,397,98,397,96,397,94,397,93,397,91,397,90,397,88, 397,87,397,86,397,83,395,80,395,79,395,77,394,74,393,72,393,70,393,67,392,65,391,6 3,389,62,388,59,386,57,383,54,383,52,381,49,379,48,378,47,376,46,375,44,374,43,372 ,43,370,42,369,42,368,42,364,41,362,41,359,41,355,41,351,42,349,42,347,42,346,44,3 43,44,342,45,339,46,337,47,336,48,333,49,332,51,330,51,328,51,327,52,326,53,323,53 ,322,53,321,54,320,55,317,55,316,56,314,58,309,59,306,61,306,62,305,62,304,63]}
  • 55.
  • 56. Player’s chainHistory retrieved db.players.find({‘login.urlSafe’: urlSafeUid}, {chainHistory: 1}); chainHistory filtered and sorted on server, Applicable chains/steps retrieved db.chains.find({$in: chain_idArr}); Retrieved chains ordered (on server) based on previously sorted chainHistory
  • 57.
  • 58. Stats are loaded from the counting log which is essentially a bunch of counters incremented db.log.find({_id: {$in: [‘2012-06-20’, ‘2012-06-20’, ‘2012-06-20’, ‘2012-06-20’]}}); Extremely simple implementation using nested subdocuments for organization
  • 59.
  • 60. Some Additional Doodle or Die Tricks
  • 62. Alice and Bob are in an awesome group groups: { _id: ‘8rOIwh2VD’, members: [ {name: ‘Alice’, dateJoined: ‘2012-05-24’}, {name: ‘Bob’, dateJoined: ‘2012-05-25’} ] banned: [ {name: ‘Eve’, dateBanned: ‘2012-05-25’} ] } Eve tries to join despite being banned!
  • 63.
  • 64. Bugs in our code fail to detect Eve’s trickery and the update query is run! groups.update( {_id: ‘8rOIwh2VD’}, {$push: {members: {name: ‘Eve’, dateJoined: new Date()} }, }, function(err) { if (err) throw err; callback(); });
  • 65. groups: { _id: ‘8rOIwh2VD’, members: [ {name: ‘Alice’, dateJoined: ‘2012-05-24’}, {name: ‘Bob’, dateJoined: ‘2012-05-25’}, {name: ‘Eve’, dateJoined: ‘2012-05-26’} ] banned: [ {name: ‘Eve’, dateRequested: ‘2012-05-25’} ] } Blast! Eve got through! How can we help prevent this?
  • 66. Bake in our assumptions! groups.update( {_id: ‘8rOIwh2VD’, ‘members.name’: {$ne: ‘Eve’}, ‘banned.name’: {$ne: ‘Eve’}}, {$push: {members: {name: ‘Eve’, dateJoined: new Date()} }, }, function(err, updateCount) { if (err) throw err; if (updateCount !== 1) throw new Error(‘bugs!’); callback(updateCount === 1); });
  • 68. To assign a player a new chain, we only need their _id and game information players game chainHistory stats account login info
  • 69. To load a player’s profile content, we just need their history, stats, and profile info players game chainHistory stats account login info
  • 70. We need to assign Bob a new chain, lets figure out what state he needs next db.players.find({name: ‘Bob’}); This will fetch and send back the ENTIRE player object!
  • 71.
  • 72. Lets specify that we only want our “game” subdocument db.players.find({name: ‘Bob’}, {fields: [‘game’]}); Hooray! Much less to retrieve and send over the series of tubes.
  • 74. If you have information available, save it even if you don’t plan on using it! db.chains.update({_id: ‘2VmVO18hs’}, {$push: {player_id: ‘1qyY61Lu1’, state: ‘draw’, date: new Date(), content: {time: 106896, count: 27, width: 520, height: 390, step_id: ‘1i7RlFbgU’ } });
  • 76. Less obvious database structure mysql> DESC players; +----------------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------------+---------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | activeStateId | int(11) | YES | | NULL | | | activeStepId | int(11) | YES | | NULL | | +----------------+---------+------+-----+---------+-------+
  • 77. Data integrity up to application Mysql> ALTER TABLE players ADD CONSTRAINT fk_players_chains FOREIGN KEY (activeChainId) REFERENCES chains(id); /* Oh no! This is going to mess things up! */ players.update({_id: ‘c58D4’}, {$set: {‘game.activeChain_id’: ‘bad_id’}});
  • 78. No mature GUI query development tools
  • 79. If we could start over would we still use MongoDB?
  • 80. Absolutely! • NoSQL in general is great for rapid prototyping • Fantastic performance • Intuitive language keeps it easy to run one-off queries / refactor schema • Excellent (and now officially supported) Node driver
  • 81. Questions? @Zugwalt @DoodleOrDie

Editor's Notes

  1. Disclaimer: schema was originally created during Node Knockout Weekend Hackathon
  2. Disclaimer: schema was originally created during Node Knockout Weekend Hackathon