CouchDB Vs MongoDB

Gabriele Lana
Gabriele LanaTechnical Trainer presso Avanscoperta um Avanscoperta
VS
Database
No SQL
Key-Value Database
Document Database
Document
         {
             "day": [ 2010, 01, 23 ],
             "products": {
                 "apple": {
                     "price": 10



Key ->
                     "quantity": 6
                 },
                 "kiwi": {
                     "price": 20
                     "quantity": 2
                 }
             },
             "checkout": 100
         }
Couchdb                           Mongodb

Data Model      Document-Oriented (JSON)           Document-Oriented (BSON)


 Interface              HTTP/REST                 Custom protocol over TCP/IP


  Object                                          Database contains Collections
                Database contains Documents
  Storage                                        Collections contains Documents

                                                 Map/Reduce (javascript) creating
  Query       Map/Reduce (javascript + others)
                                                 Collections + Object-Based query
  Method       creating Views + Range queries
                                                              language
                 Master-Master with custom
Replication                                                Master-Slave
                 conflict resolution functions

              MVCC (Multi Version Concurrency
Concurrency                                              Update in-place
                        Control)


 Written In                Erlang                             C++
Map/Reduce???
Example: Tickets




{                      {                      {                      {
    "id": 1,               "id": 2,               "id": 3,               "id": 4,
    "day": 20100123,       "day": 20100123,       "day": 20100123,       "day": 20100123,
    "checkout": 100        "checkout": 42         "checkout": 215        "checkout": 73
}                      }                      }                      }
Sum(checkout)?




{                      {                      {                      {
    "id": 1,               "id": 2,               "id": 3,               "id": 4,
    "day": 20100123,       "day": 20100123,       "day": 20100123,       "day": 20100123,
    "checkout": 100        "checkout": 42         "checkout": 215        "checkout": 73
}                      }                      }                      }
Map: emit(checkout)




       100                     42                    215                     73


{                      {                      {                      {
    "id": 1,               "id": 2,               "id": 3,               "id": 4,
    "day": 20100123,       "day": 20100123,       "day": 20100123,       "day": 20100123,
    "checkout": 100        "checkout": 42         "checkout": 215        "checkout": 73
}                      }                      }                      }
Reduce: sum(checkouts)



                   142                                          288



        100                     42                    215                     73


 {                      {                      {                      {
     "id": 1,               "id": 2,               "id": 3,               "id": 4,
     "day": 20100123,       "day": 20100123,       "day": 20100123,       "day": 20100123,
     "checkout": 100        "checkout": 42         "checkout": 215        "checkout": 73
 }                      }                      }                      }
Reduce: sum(checkouts)

                                         430



                   142                                          288



        100                     42                    215                     73


 {                      {                      {                      {
     "id": 1,               "id": 2,               "id": 3,               "id": 4,
     "day": 20100123,       "day": 20100123,       "day": 20100123,       "day": 20100123,
     "checkout": 100        "checkout": 42         "checkout": 215        "checkout": 73
 }                      }                      }                      }
Reduce must be associative

reduce(         100         42        215          73    ) ==   430




                      Must be equal to
reduce(

       reduce(        100        42         ) ==        142



       reduce(        215        73         ) ==        288




) ==      430
SELECT
SUM(checkout)
 FROM ticket
    ?!?!?!?
Inherently distributed

                                        430



                  142                                          288



       100                     42                     215                    73


{                      {                      {                      {
    "id": 1,               "id": 2,               "id": 3,               "id": 4,
    "day": 20100123,       "day": 20100123,       "day": 20100123,       "day": 20100123,
    "checkout": 100        "checkout": 42         "checkout": 215        "checkout": 73
}                      }                      }                      }
Logaritmic Update

                                        430



                  142                                          288



       100                     42                     215                    73


{                      {                      {                      {
    "id": 1,               "id": 2,               "id": 3,               "id": 4,
    "day": 20100123,       "day": 20100123,       "day": 20100123,       "day": 20100123,
    "checkout": 100        "checkout": 42         "checkout": 210        "checkout": 73
}                      }                      }                      }
Logaritmic Update

                                        430



                  142                                          288



       100                     42                     210                    73


{                      {                      {                      {
    "id": 1,               "id": 2,               "id": 3,               "id": 4,
    "day": 20100123,       "day": 20100123,       "day": 20100123,       "day": 20100123,
    "checkout": 100        "checkout": 42         "checkout": 210        "checkout": 73
}                      }                      }                      }
Logaritmic Update

                                        430



                  142                                          283



       100                     42                     210                    73


{                      {                      {                      {
    "id": 1,               "id": 2,               "id": 3,               "id": 4,
    "day": 20100123,       "day": 20100123,       "day": 20100123,       "day": 20100123,
    "checkout": 100        "checkout": 42         "checkout": 210        "checkout": 73
}                      }                      }                      }
Logaritmic Update

                                        425



                  142                                          283



       100                     42                     210                    73


{                      {                      {                      {
    "id": 1,               "id": 2,               "id": 3,               "id": 4,
    "day": 20100123,       "day": 20100123,       "day": 20100123,       "day": 20100123,
    "checkout": 100        "checkout": 42         "checkout": 210        "checkout": 73
}                      }                      }                      }
Logaritmic Update
Sum(checkout)
Sum(checkout)
Sum(checkout)
Sum(checkout)
Sum(checkout)
# START SERVER
$ ~/opt/mongodb-1.3.0/bin/mongod 
  --dbpath=./db/mongodb.01/ 
  --logpath=./log/mongodb.01 
  --port 30001



# START SHELL
$ ~/opt/mongodb-1.3.0/bin/mongo localhost:30001
connecting to: localhost:30001/test
type "help" for help
> show dbs
admin
local
Sum(checkout)
> use checkout
switched to db checkout

>   db.tickets.save({   "_id":   1,   "day":   20100123,   "checkout":   100 })
>   db.tickets.save({   "_id":   2,   "day":   20100123,   "checkout":   42 })
>   db.tickets.save({   "_id":   3,   "day":   20100123,   "checkout":   215 })
>   db.tickets.save({   "_id":   4,   "day":   20100123,   "checkout":   73 })

> db.tickets.count()
4

> db.tickets.find()
{ "_id" : 1, "day" : 20100123, "checkout" : 100 }
...

> db.tickets.find({ "_id": 1 })
{ "_id" : 1, "day" : 20100123, "checkout" : 100 }
Sum(checkout)
> var map = function() {
... emit(null, this.checkout)
... }

> var reduce = function(key, values) {
... var sum = 0
... for (var index in values) sum += values[index]
... return sum
... }
Sum(checkout)
                               Temporary Collection
> sumOfCheckouts = db.tickets.mapReduce(map, reduce)
{
  "result" : "tmp.mr.mapreduce_1263717818_4",
  "timeMillis" : 8,
  "counts" : { "input" : 4, "emit" : 4, "output" : 1 },
  "ok" : 1
}

> db.getCollectionNames()
[
  "tickets",
  "tmp.mr.mapreduce_1263717818_4",
]

> db[sumOfCheckouts.result].find()
{ "_id" : null, "value" : 430 }
Sum(checkout)
                                  Persistent Collection
> db.tickets.mapReduce(map, reduce, { “out”: “sumOfCheckouts” })

> db.getCollectionNames()
[
  “sumOfCheckouts”,
  "tickets",
  "tmp.mr.mapreduce_1263717818_4"
]

> db.sumOfCheckouts.find()
{ "_id" : null, "value" : 430 }

> db.sumOfCheckouts.findOne().value
430
Sum(checkout)
                                    Reduce by Group
# GROUP AS MAP/REDUCE ALTERNATIVE

> db.tickets.group({
... "initial": { "sum": 0 },
... "reduce": function(ticket, checkouts) {
...... checkouts.sum += ticket.checkout
...... }
... })
[ { "sum" : 430 } ]
Sum(checkout) Group By day




   {                      {                      {                      {
       "id": 1,               "id": 2,               "id": 3,               "id": 4,
       "day": 20100123,       "day": 20100124,       "day": 20100123,       "day": 20100124,
       "checkout": 100        "checkout": 42         "checkout": 215        "checkout": 73
   }                      }                      }                      }
Map: emit(day,checkout)




 “20100123”:100         “20100124”:42          “20100123”:215         “20100124”:73




 {                      {                      {                      {
     "id": 1,               "id": 2,               "id": 3,               "id": 4,
     "day": 20100123,       "day": 20100124,       "day": 20100123,       "day": 20100124,
     "checkout": 100        "checkout": 42         "checkout": 215        "checkout": 73
 }                      }                      }                      }
Reduce: sum(checkouts)


                  “20100123”:315




 “20100123”:100         “20100124”:42          “20100123”:215         “20100124”:73




 {                      {                      {                      {
     "id": 1,               "id": 2,               "id": 3,               "id": 4,
     "day": 20100123,       "day": 20100124,       "day": 20100123,       "day": 20100124,
     "checkout": 100        "checkout": 42         "checkout": 215        "checkout": 73
 }                      }                      }                      }
Reduce: sum(checkouts)


                  “20100123”:315                        “20100124”:115




 “20100123”:100         “20100124”:42          “20100123”:215         “20100124”:73




 {                      {                      {                      {
     "id": 1,               "id": 2,               "id": 3,               "id": 4,
     "day": 20100123,       "day": 20100124,       "day": 20100123,       "day": 20100124,
     "checkout": 100        "checkout": 42         "checkout": 215        "checkout": 73
 }                      }                      }                      }
Sum(checkout)
 Group By day
Sum(checkout)
 Group By day
Design Documents are
          Documents
Design Documents are
          Documents
Non trivial Map:
Calculate Checkout
Non trivial Map:
Calculate Checkout
Non trivial Map:
Calculate Checkout
Structured Keys and
       Group Levels
Structured Keys and
       Group Levels
Structured Keys and
       Group Levels
Structured Keys and
       Group Levels
Structured Keys and
       Group Levels
Structured Keys and
       Group Levels
Structured Keys and
       Group Levels
Sum(Checkout) by day
                            Update In-Place
> db.tickets.update({ "_id": 1 }, {
... $set: { "products": {
...... "apple": { "quantity": 5, "price": 10 },
...... "kiwi": { "quantity": 2, "price": 25 }
...... }
... },
... $unset: { "checkout": 1 }
... })

> db.tickets.find()
{ "_id" : 1, "day" : 20100123, "products" : {
   "apple" : { "quantity" : 5, "price" : 10 },
   "kiwi" : { "quantity" : 2, "price" : 25 }
}}
{ "_id" : 2, "day" : 20100123, "checkout" : 42 }
{ "_id" : 3, "day" : 20100123, "checkout" : 215 }
{ "_id" : 4, "day" : 20100123, "checkout" : 73 }
Sum(Checkout) by day
                         Calculate Checkout
> db.tickets.find()
{ "_id" : 1, "day" : 20100123, "products" : {
  "apple" : { "quantity" : 5, "price" : 10 },
  "kiwi" : { "quantity" : 2, "price" : 25 } } }

{ "_id" : 2, "day" : 20100124, "products" : {
  "banana" : { "quantity" : 2, "price" : 20 } } }

{ "_id" : 3, "day" : 20100123, "products" : {
  "kiwi" : { "quantity" : 4, "price" : 25 },
  "babana" : { "quantity" : 5, "price" : 20 },
  "lemon" : { "quantity" : 3, "price" : 5 } } }

{ "_id" : 4, "day" : 20100124, "products" : {
  "kiwi" : { "quantity" : 2, "price" : 25 },
  "babana" : { "quantity" : 1, "price" : 20 } } }
Sum(Checkout) by day
                         Calculate Checkout
> var map = function() {
... var checkout = 0
... for (var name in this.products) {
...... var product = this.products[name]
...... checkout += product.quantity * product.price
...... }
... emit(this.day, checkout)
}

> var reduce = function(key, values) {
... var sum = 0
... for (var index in values) sum += values[index]
... return sum
}
Sum(Checkout) by day
                         Calculate Checkout
> db.tickets.mapReduce(map, reduce, { "out": "sumOfCheckouts" })

> db.sumOfCheckouts.find()
{ "_id" : 20100123, "value" : 315 }
{ "_id" : 20100124, "value" : 110 }
Sum(Checkout) by day
                           Data Normalization
> db.tickets.find()
{ "_id" : 1, "day" : 20100123, "products"   : {
  "apple" : 5, "kiwi" : 2 } }
{ "_id" : 2, "day" : 20100124, "products"   : {
  "banana" : 2 } }
{ "_id" : 3, "day" : 20100123, "products"   : {
  "kiwi" : 4, "banana" : 5, "lemon" : 3 }   }
{ "_id" : 4, "day" : 20100124, "products"   : {
  "kiwi" : 2, "banana" : 1 } }

>   db.product.find()
{   "_id" : "apple", "price" : 10 }
{   "_id" : "kiwi", "price" : 25 }
{   "_id" : "banana", "price" : 20 }
{   "_id" : "lemon", "price" : 5 }
Sum(Checkout) by day
                         Data Normalization
> var map = function() {
... var checkout = 0
... for (var name in this.products) {
...... var quantity = this.products[name]
...... var price = db.product.findOne({ "_id": name }).price
...... checkout += quantity * price
...... }
... emit(this.day, checkout)
}

> var reduce = function(key, values) {
... var sum = 0
... for (var index in values) sum += values[index]
... return sum
}
Sum(Checkout) by day
                         Data Normalization
> db.tickets.mapReduce(map, reduce, { "out": "sumOfCheckouts" })

> db.sumOfCheckouts.find()
{ "_id" : 20100123, "value" : 315 }
{ "_id" : 20100124, "value" : 110 }
Count of unique
                                                  elements?
>   db.view.find();
{   "user" : "001",   "page"   :   "example.com/001",   "time"   :   2 }
{   "user" : "001",   "page"   :   "example.com/002",   "time"   :   4 }
{   "user" : "002",   "page"   :   "example.com/001",   "time"   :   6 }
{   "user" : "002",   "page"   :   "example.com/002",   "time"   :   10 }
{   "user" : "002",   "page"   :   "example.com/002",   "time"   :   12 }
{   "user" : "002",   "page"   :   "example.com/003",   "time"   :   1 }
{   "user" : "003",   "page"   :   "example.com/001",   "time"   :   42 }
{   "user" : "003",   "page"   :   "example.com/001",   "time"   :   9 }

# USER NAVIGATION SURVEY = FOR EACH USER
  # NUMBER OF UNIQUE PAGES
  # AVERAGE TIME ON A PAGE
Count of unique
                                          elements?
> var map = function() {
... var accumulator = {
...... "numberOfViews": 1,
...... "visitedPages": {},
...... "totalTime": 0
...... };

... accumulator["visitedPages"][this.page] = 1
... accumulator["totalTime"] += this.time
... emit(this.user, accumulator)
}
Count of unique
                                             elements?
# EASY TO DEBUG

> var aUser = db.view.findOne({ "user": "001" })

> var emit = function(id, value) { print(tojson(value)) }

> map.call(aUser)
{
        "numberOfViews" : 1,
        "visitedPages" : {
                "example.com/001" : 1
        },
        "totalTime" : 2
}
Count of unique
                                                  elements?
> var reduce = function(key, values) {
... var accumulator = {
...... "numberOfViews": 0,
...... "visitedPages": {},
...... "totalTime": 0
...... };

... values.forEach(function(value) {
...... accumulator["numberOfViews"] += value["numberOfViews"]
...... accumulator["totalTime"] += value["totalTime"]

...... for (var page in value["visitedPages"]) {
......... if (accumulator["visitedPages"][page] === undefined) {
............ accumulator["visitedPages"][page] = 0
......... }
......... accumulator["visitedPages"][page] += 1
...... }
... })

... return accumulator
}
Count of unique
                                            elements?
> db.view.mapReduce(map, reduce,
  { "out": "userNavigationSurvey" })

# NOT AS WE WANTED

> db.userNavigationSurvey.find()
{ "_id" : "001", "value" : {
  "numberOfViews" : 2,
  "visitedPages" : {
    "example.com/001" : 1,
    "example.com/002" : 1 },
  "totalTime" : 6 } }

{ "_id" : "002", "value" : {
  "numberOfViews" : 4,
  "visitedPages" : {
    ...
Count of unique
                                          elements?
> var finalize = function(key, accumulator) {
... accumulator["averageTime"] =
...... accumulator["totalTime"] / accumulator["numberOfViews"]
... accumulator["numberOfUniquePages"] = 0
... for (var page in accumulator["visitedPages"]) {
...... accumulator["numberOfUniquePages"] += 1
... }
... delete accumulator["totalTime"]
... delete accumulator["numberOfViews"]
... delete accumulator["visitedPages"]
... return accumulator
}
Count of unique
                                          elements?
> db.view.mapReduce(map, reduce, {
... "finalize": finalize,
... "out": "userNavigationSurvey"
})

> db.userNavigationSurvey.find()
{ "_id" : "001", "value" : {
  "averageTime" : 3, "numberOfUniquePages" : 2 } }

{ "_id" : "002", "value" : {
  "averageTime" : 7.25, "numberOfUniquePages" : 3 } }

{ "_id" : "003", "value" : {
  "averageTime" : 25.5, "numberOfUniquePages" : 1 } }
CouchDB Vs MongoDB
Count of unique
                                       elements by steps
# STEP 1: CREATE THE BASE COLLECTION (WITHOUT UNIQUE ELEMENTS)

> var mapBase = function() {
... emit(this.user, {
...... "numberOfViews": 1,
...... "totalTime": this.time
... })
}

> var reduceBase = function(key, values) {
... var accumulator = {
...... "numberOfViews": 0,
...... "totalTime": 0
... };
... values.forEach(function(value) {
...... accumulator["numberOfViews"] += value["numberOfViews"]
...... accumulator["totalTime"] += value["totalTime"]
... })
... return accumulator
}
Count of unique
                                         elements by steps
> var finalizeBase = function(key, accumulator) {
... accumulator["numberOfUniquePages"] = 0
... accumulator["averageTime"] =
...... accumulator["totalTime"] / accumulator["numberOfViews"]
... delete accumulator["totalTime"]
... delete accumulator["numberOfViews"]
... return accumulator
}

> db.view.mapReduce(mapBase, reduceBase, {
   "finalize": finalizeBase,
   "out": "userNavigationSurvey"
})

>   db.userNavigationSurvey.find()
{   "_id" : "001", "value" : { "numberOfUniquePages" : 0, "averageTime" : 3 } }
{   "_id" : "002", "value" : { "numberOfUniquePages" : 0, "averageTime" : 7.25 } }
{   "_id" : "003", "value" : { "numberOfUniquePages" : 0, "averageTime" : 25.5 } }
Count of unique
                                          elements by steps
# STEP 2: CREATE THE COLLECTION OF UNIQUE ELEMENTS

> var mapUniquePages = function() {
... emit(this.user + "-" + this.page, {
...... "user": this.user,
...... "page": this.page
... })
}

> var reduceUniquePages = function(key, values) {
... return values[0]
}

> db.view.mapReduce(mapUniquePages, reduceUniquePages {
   "out": "userUniquePages"
})
Count of unique
                                       elements by steps
> db.userUniquePages.find()

{ "_id" : "001-example.com/001", "value" : {
   "user" : "001", "page" : "example.com/001" } }

{ "_id" : "001-example.com/002", "value" : {
   "user" : "001", "page" : "example.com/002" } }

{ "_id" : "002-example.com/001", "value" : {
   "user" : "002", "page" : "example.com/001" } }

{ "_id" : "002-example.com/002", "value" : {
   "user" : "002", "page" : "example.com/002" } }

{ "_id" : "002-example.com/003", "value" : {
   "user" : "002", "page" : "example.com/003" } }

{ "_id" : "003-example.com/001", "value" : {
   "user" : "003", "page" : "example.com/001" } }
Count of unique
                                         elements by steps
# STEP 3: UPDATE BASE COLLECTION WITH UNIQUE ELEMENTS COUNT

> db.userUniquePages.find().forEach(function(userUniquePage) {
        db.userNavigationSurvey.update(
                { "_id": userUniquePage.value.user },
                { $inc: { "value.numberOfUniquePages": 1 } }
        )
})

>   db.userNavigationSurvey.find()
{   "_id" : "001", "value" : { "numberOfUniquePages" : 2, "averageTime" : 3 } }
{   "_id" : "002", "value" : { "numberOfUniquePages" : 3, "averageTime" : 7.25 } }
{   "_id" : "003", "value" : { "numberOfUniquePages" : 1, "averageTime" : 25.5 } }
Architecture

          Webmachine




HTTP




             HTTP


 HTTP
Scalability

        Webmachine




Nginx




                         Master/Master

        Webmachine
User Account
Message
Received by <account>
                          After <timestamp>?

function(document) {
    if (document.from && document.to) {
        var key = [ document.to, document.timestamp ]
        var content = document._attachments["content"]
        var outline = {
            "id": document._id,
            "from": document.from,
            "timestamp": document.timestamp,
            "type": content["content_type"],
            "length": content["length"],
        }
        emit(key, outline)
    }
}
Received by <account>
  After <timestamp>?
Received by <account>
                               After <timestamp>?

> curl -X GET ".../mercurio/_design/message/_view/received_after"

{ "total_rows":3, "offset":0, "rows": [
    {
        "id": "ff35356344ee0e9928c212b52e36e6f3",
        "key": [ "gabriele", 1263655442 ],
        "value": {
            "id": "ff35356344ee0e9928c212b52e36e6f3",
            "from": "chiara",
            "timestamp": 1263655442,
            "type": "text/plain;charset=utf-8",
            "length": 16
        }
    },
    ...
}
Results are
                                      ordered by Key
{ "key": [ "chiara", 126 ],
  "value": {
    "id": "ff35356344ee0e992...",
    "from": "gabriele"               [ "chiara", 126 ]
  }



                                         ==       <
}



{ "key": [ "chiara", 128 ],
  "value": {
    "id": "0deff99666425bacc...",    [ "chiara", 128 ]
    "from": "gabriele"
  }


                                          <
}



{ "key": [ "gabriele", 120 ],
  "value": {
    "id": "9842063609746c661...",   [ "gabriele", 120 ]
    "from": "chiara"
  }
}
Select with Key

{ "key": [ "chiara", 126 ],
  "value": {
    "id": "ff35356344ee0e992...",
                                    received_after?
  }
    "from": "gabriele"
                                      key=["chiara",126]
}



{ "key": [ "chiara", 128 ],
  "value": {
    "id": "0deff99666425bacc...",
    "from": "gabriele"
  }
}



{ "key": [ "gabriele", 120 ],
  "value": {
    "id": "9842063609746c661...",
    "from": "chiara"
  }
}
Select with range of Keys

{ "key": [ "chiara", 126 ],         received_after?
  "value": {
    "id": "ff35356344ee0e992...",
    "from": "gabriele"
                                      startkey=["chiara",126]&
}
  }
                                      endkey=["gabriele",0]

{ "key": [ "chiara", 128 ],
  "value": {
    "id": "0deff99666425bacc...",
    "from": "gabriele"
  }
}



{ "key": [ "gabriele", 120 ],
  "value": {
    "id": "9842063609746c661...",
    "from": "chiara"
  }
}
Select with range of Keys

{ "key": [ "chiara", 126 ],
  "value": {
    "id": "ff35356344ee0e992...",
    "from": "gabriele"
  }
}
                                     [ "chiara", [] ]

{ "key": [ "chiara", 128 ],
  "value": {
    "id": "0deff99666425bacc...",
    "from": "gabriele"
  }
                                    { "key": [ "chiara", [] ],
}
                                      "value": {
                                        "id": "0deff99666425bacc...",
                                        "from": "gabriele"
{ "key": [ "gabriele", 120 ],         }
  "value": {                        }
    "id": "9842063609746c661...",
    "from": "chiara"
  }
}
Select with range of Keys

{ "key": [ "chiara", 126 ],         received_after?
  "value": {
    "id": "ff35356344ee0e992...",
    "from": "gabriele"
                                      startkey=["chiara",126]&
}
  }
                                      endkey=["chiara",[]]

{ "key": [ "chiara", 128 ],
  "value": {
    "id": "0deff99666425bacc...",
    "from": "gabriele"
  }
}



{ "key": [ "gabriele", 120 ],
  "value": {
    "id": "9842063609746c661...",
    "from": "chiara"
  }
}
Received by “chiara”
                                              After 126
{ "key": [ "chiara", 126 ],         received_after?
  "value": {
    "id": "ff35356344ee0e992...",
    "from": "gabriele"
                                      startkey=["chiara",127]&
}
  }
                                      endkey=["chiara",[]]

{ "key": [ "chiara", 128 ],
  "value": {
    "id": "0deff99666425bacc...",
    "from": "gabriele"
  }
}



{ "key": [ "gabriele", 120 ],
  "value": {
    "id": "9842063609746c661...",
    "from": "chiara"
  }
}
Push Received
             Messages from Server



Check for Messages           _changes?
  received by <account.id>     filter=message/received&
  after <timestamp>            by=<account.id>&
                               after=<timestamp>

     Send Message               Save Document
     to <account.id>              to: <account.id>
Push Received
                         Messages from Server

_changes?filter=message/received&by=<account.id>&after=<timestamp>



    function(document, request) {
        var receivedByMe =
            document.to === request.query.by

        var receivedAfterLastTime =
            document.receivedAt >= request.query.after

        return receivedByMe && receivedAfterLastTime
    }
Backoffice as
Couch Application
1 von 85

Recomendados

5. IO virtualization von
5. IO virtualization5. IO virtualization
5. IO virtualizationHwanju Kim
10.3K views32 Folien
Introduction to OpenMP von
Introduction to OpenMPIntroduction to OpenMP
Introduction to OpenMPAkhila Prabhakaran
1.6K views42 Folien
Syed IoT - module 5 von
Syed  IoT - module 5Syed  IoT - module 5
Syed IoT - module 5Syed Mustafa
14.6K views78 Folien
Google App Engine von
Google App EngineGoogle App Engine
Google App EngineSoftware Park Thailand
11.2K views67 Folien
Synchronization - Election Algorithms von
Synchronization  - Election AlgorithmsSynchronization  - Election Algorithms
Synchronization - Election AlgorithmsOsaMa Hasan
8K views30 Folien
Grid computing von
Grid computingGrid computing
Grid computingKeshab Nath
7.6K views32 Folien

Más contenido relacionado

Was ist angesagt?

Graphical password authentication system with association of sound von
Graphical password authentication system with association of soundGraphical password authentication system with association of sound
Graphical password authentication system with association of soundVikram Verma
6.7K views16 Folien
OpenGL Mini Projects With Source Code [ Computer Graphics ] von
OpenGL Mini Projects With Source Code [ Computer Graphics ]OpenGL Mini Projects With Source Code [ Computer Graphics ]
OpenGL Mini Projects With Source Code [ Computer Graphics ]Daffodil International University
56.9K views39 Folien
Research in Internet of Things' Operating Systems (IoT OS's) von
Research in Internet of Things' Operating Systems (IoT OS's)Research in Internet of Things' Operating Systems (IoT OS's)
Research in Internet of Things' Operating Systems (IoT OS's)Salahuddin ElKazak
6.2K views25 Folien
Hadoop von
Hadoop Hadoop
Hadoop ABHIJEET RAJ
525 views31 Folien
Understanding and Testing DDR4 R-DIMM and LR-DIMM Technology von
Understanding and Testing DDR4 R-DIMM and LR-DIMM TechnologyUnderstanding and Testing DDR4 R-DIMM and LR-DIMM Technology
Understanding and Testing DDR4 R-DIMM and LR-DIMM TechnologyIntegrated Device Technology
4.4K views10 Folien
9 Real Life Applications of Java von
9 Real Life Applications of Java9 Real Life Applications of Java
9 Real Life Applications of JavaPrachiVarshney7
178 views11 Folien

Was ist angesagt?(20)

Graphical password authentication system with association of sound von Vikram Verma
Graphical password authentication system with association of soundGraphical password authentication system with association of sound
Graphical password authentication system with association of sound
Vikram Verma6.7K views
Research in Internet of Things' Operating Systems (IoT OS's) von Salahuddin ElKazak
Research in Internet of Things' Operating Systems (IoT OS's)Research in Internet of Things' Operating Systems (IoT OS's)
Research in Internet of Things' Operating Systems (IoT OS's)
Salahuddin ElKazak6.2K views
IoT Cloud architecture von MachinePulse
IoT Cloud architectureIoT Cloud architecture
IoT Cloud architecture
MachinePulse37.1K views
Introduction to Internet of Things Hardware von Daniel Eichhorn
Introduction to Internet of Things HardwareIntroduction to Internet of Things Hardware
Introduction to Internet of Things Hardware
Daniel Eichhorn5.4K views
Middleware in Distributed System-RPC,RMI von Prajakta Rane
Middleware in Distributed System-RPC,RMIMiddleware in Distributed System-RPC,RMI
Middleware in Distributed System-RPC,RMI
Prajakta Rane199 views
CS8662 Mobile Application Development Lab Manual von pkaviya
CS8662 Mobile Application Development Lab ManualCS8662 Mobile Application Development Lab Manual
CS8662 Mobile Application Development Lab Manual
pkaviya3.5K views
Transactions (Distributed computing) von Sri Prasanna
Transactions (Distributed computing)Transactions (Distributed computing)
Transactions (Distributed computing)
Sri Prasanna7.7K views
15CS81- IoT Module-2 von Syed Mustafa
15CS81- IoT Module-215CS81- IoT Module-2
15CS81- IoT Module-2
Syed Mustafa13.3K views
Flynns classification von Yasir Khan
Flynns classificationFlynns classification
Flynns classification
Yasir Khan82.5K views
Mobile Software Engineering (at University of Cambridge Wednesday Seminars) von 3scale.net
Mobile Software Engineering (at University of Cambridge Wednesday Seminars)Mobile Software Engineering (at University of Cambridge Wednesday Seminars)
Mobile Software Engineering (at University of Cambridge Wednesday Seminars)
3scale.net7.3K views
Computer science seminar topics von 123seminarsonly
Computer science seminar topicsComputer science seminar topics
Computer science seminar topics
123seminarsonly134.8K views
CSE Final Year Project Presentation on Android Application von Ahammad Karim
CSE Final Year Project Presentation on Android ApplicationCSE Final Year Project Presentation on Android Application
CSE Final Year Project Presentation on Android Application
Ahammad Karim53.4K views

Similar a CouchDB Vs MongoDB

Apéro RubyBdx - MongoDB - 8-11-2011 von
Apéro RubyBdx - MongoDB - 8-11-2011Apéro RubyBdx - MongoDB - 8-11-2011
Apéro RubyBdx - MongoDB - 8-11-2011pierrerenaudin
701 views39 Folien
Living in eventually consistent reality von
Living in eventually consistent realityLiving in eventually consistent reality
Living in eventually consistent realityBartosz Sypytkowski
473 views98 Folien
MongoDB for Time Series Data Part 2: Analyzing Time Series Data Using the Agg... von
MongoDB for Time Series Data Part 2: Analyzing Time Series Data Using the Agg...MongoDB for Time Series Data Part 2: Analyzing Time Series Data Using the Agg...
MongoDB for Time Series Data Part 2: Analyzing Time Series Data Using the Agg...MongoDB
51.1K views47 Folien
MongoDB Analytics von
MongoDB AnalyticsMongoDB Analytics
MongoDB Analyticsdatablend
2.2K views23 Folien
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015) von
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)Dan Robinson
1.8K views56 Folien
MongoDB for Time Series Data: Analyzing Time Series Data Using the Aggregatio... von
MongoDB for Time Series Data: Analyzing Time Series Data Using the Aggregatio...MongoDB for Time Series Data: Analyzing Time Series Data Using the Aggregatio...
MongoDB for Time Series Data: Analyzing Time Series Data Using the Aggregatio...MongoDB
4.1K views58 Folien

Similar a CouchDB Vs MongoDB(7)

Apéro RubyBdx - MongoDB - 8-11-2011 von pierrerenaudin
Apéro RubyBdx - MongoDB - 8-11-2011Apéro RubyBdx - MongoDB - 8-11-2011
Apéro RubyBdx - MongoDB - 8-11-2011
pierrerenaudin701 views
MongoDB for Time Series Data Part 2: Analyzing Time Series Data Using the Agg... von MongoDB
MongoDB for Time Series Data Part 2: Analyzing Time Series Data Using the Agg...MongoDB for Time Series Data Part 2: Analyzing Time Series Data Using the Agg...
MongoDB for Time Series Data Part 2: Analyzing Time Series Data Using the Agg...
MongoDB51.1K views
MongoDB Analytics von datablend
MongoDB AnalyticsMongoDB Analytics
MongoDB Analytics
datablend2.2K views
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015) von Dan Robinson
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Dan Robinson1.8K views
MongoDB for Time Series Data: Analyzing Time Series Data Using the Aggregatio... von MongoDB
MongoDB for Time Series Data: Analyzing Time Series Data Using the Aggregatio...MongoDB for Time Series Data: Analyzing Time Series Data Using the Aggregatio...
MongoDB for Time Series Data: Analyzing Time Series Data Using the Aggregatio...
MongoDB4.1K views
Detection of errors and potential vulnerabilities in C and C++ code using the... von Andrey Karpov
Detection of errors and potential vulnerabilities in C and C++ code using the...Detection of errors and potential vulnerabilities in C and C++ code using the...
Detection of errors and potential vulnerabilities in C and C++ code using the...
Andrey Karpov95 views

Más de Gabriele Lana

Microservice Architectures von
Microservice ArchitecturesMicroservice Architectures
Microservice ArchitecturesGabriele Lana
276 views44 Folien
Professional Programmer 2018 von
Professional Programmer 2018Professional Programmer 2018
Professional Programmer 2018Gabriele Lana
1.7K views34 Folien
Beyond Phoenix von
Beyond PhoenixBeyond Phoenix
Beyond PhoenixGabriele Lana
1.3K views26 Folien
Parse Everything With Elixir von
Parse Everything With ElixirParse Everything With Elixir
Parse Everything With ElixirGabriele Lana
3.9K views63 Folien
The Magic Of Elixir von
The Magic Of ElixirThe Magic Of Elixir
The Magic Of ElixirGabriele Lana
3.9K views96 Folien
Professional Programmer (3 Years Later) von
Professional Programmer (3 Years Later)Professional Programmer (3 Years Later)
Professional Programmer (3 Years Later)Gabriele Lana
2.8K views31 Folien

Más de Gabriele Lana(20)

Microservice Architectures von Gabriele Lana
Microservice ArchitecturesMicroservice Architectures
Microservice Architectures
Gabriele Lana276 views
Professional Programmer 2018 von Gabriele Lana
Professional Programmer 2018Professional Programmer 2018
Professional Programmer 2018
Gabriele Lana1.7K views
Parse Everything With Elixir von Gabriele Lana
Parse Everything With ElixirParse Everything With Elixir
Parse Everything With Elixir
Gabriele Lana3.9K views
Professional Programmer (3 Years Later) von Gabriele Lana
Professional Programmer (3 Years Later)Professional Programmer (3 Years Later)
Professional Programmer (3 Years Later)
Gabriele Lana2.8K views
Resource Oriented Design von Gabriele Lana
Resource Oriented DesignResource Oriented Design
Resource Oriented Design
Gabriele Lana3.8K views
Agileday Coderetreat 2013 von Gabriele Lana
Agileday Coderetreat 2013Agileday Coderetreat 2013
Agileday Coderetreat 2013
Gabriele Lana5.5K views
Milano Legacy Coderetreat 2013 von Gabriele Lana
Milano Legacy Coderetreat 2013Milano Legacy Coderetreat 2013
Milano Legacy Coderetreat 2013
Gabriele Lana1.7K views
Professional Programmer von Gabriele Lana
Professional ProgrammerProfessional Programmer
Professional Programmer
Gabriele Lana9.2K views
It is not supposed to fly but it does von Gabriele Lana
It is not supposed to fly but it doesIt is not supposed to fly but it does
It is not supposed to fly but it does
Gabriele Lana5.7K views
Introduction to Nodejs von Gabriele Lana
Introduction to NodejsIntroduction to Nodejs
Introduction to Nodejs
Gabriele Lana17.6K views
Nodejs Explained with Examples von Gabriele Lana
Nodejs Explained with ExamplesNodejs Explained with Examples
Nodejs Explained with Examples
Gabriele Lana112.3K views

Último

Roadmap to Become Experts.pptx von
Roadmap to Become Experts.pptxRoadmap to Become Experts.pptx
Roadmap to Become Experts.pptxdscwidyatamanew
14 views45 Folien
virtual reality.pptx von
virtual reality.pptxvirtual reality.pptx
virtual reality.pptxG036GaikwadSnehal
11 views15 Folien
Business Analyst Series 2023 - Week 3 Session 5 von
Business Analyst Series 2023 -  Week 3 Session 5Business Analyst Series 2023 -  Week 3 Session 5
Business Analyst Series 2023 - Week 3 Session 5DianaGray10
237 views20 Folien
Microsoft Power Platform.pptx von
Microsoft Power Platform.pptxMicrosoft Power Platform.pptx
Microsoft Power Platform.pptxUni Systems S.M.S.A.
52 views38 Folien
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLive von
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 CiscoLiveNetwork Automation Forum
30 views35 Folien
6g - REPORT.pdf von
6g - REPORT.pdf6g - REPORT.pdf
6g - REPORT.pdfLiveplex
10 views23 Folien

Último(20)

Business Analyst Series 2023 - Week 3 Session 5 von DianaGray10
Business Analyst Series 2023 -  Week 3 Session 5Business Analyst Series 2023 -  Week 3 Session 5
Business Analyst Series 2023 - Week 3 Session 5
DianaGray10237 views
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLive von 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
6g - REPORT.pdf von Liveplex
6g - REPORT.pdf6g - REPORT.pdf
6g - REPORT.pdf
Liveplex10 views
Five Things You SHOULD Know About Postman von Postman
Five Things You SHOULD Know About PostmanFive Things You SHOULD Know About Postman
Five Things You SHOULD Know About Postman
Postman30 views
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院 von IttrainingIttraining
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院
HTTP headers that make your website go faster - devs.gent November 2023 von Thijs Feryn
HTTP headers that make your website go faster - devs.gent November 2023HTTP headers that make your website go faster - devs.gent November 2023
HTTP headers that make your website go faster - devs.gent November 2023
Thijs Feryn21 views
Perth MeetUp November 2023 von Michael Price
Perth MeetUp November 2023 Perth MeetUp November 2023
Perth MeetUp November 2023
Michael Price19 views
DALI Basics Course 2023 von Ivory Egg
DALI Basics Course  2023DALI Basics Course  2023
DALI Basics Course 2023
Ivory Egg16 views
Igniting Next Level Productivity with AI-Infused Data Integration Workflows von Safe Software
Igniting Next Level Productivity with AI-Infused Data Integration Workflows Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Safe Software257 views
TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensors von 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
sugiuralab19 views
Case Study Copenhagen Energy and Business Central.pdf von Aitana
Case Study Copenhagen Energy and Business Central.pdfCase Study Copenhagen Energy and Business Central.pdf
Case Study Copenhagen Energy and Business Central.pdf
Aitana16 views

CouchDB Vs MongoDB

  • 1. VS
  • 6. Document { "day": [ 2010, 01, 23 ], "products": { "apple": { "price": 10 Key -> "quantity": 6 }, "kiwi": { "price": 20 "quantity": 2 } }, "checkout": 100 }
  • 7. Couchdb Mongodb Data Model Document-Oriented (JSON) Document-Oriented (BSON) Interface HTTP/REST Custom protocol over TCP/IP Object Database contains Collections Database contains Documents Storage Collections contains Documents Map/Reduce (javascript) creating Query Map/Reduce (javascript + others) Collections + Object-Based query Method creating Views + Range queries language Master-Master with custom Replication Master-Slave conflict resolution functions MVCC (Multi Version Concurrency Concurrency Update in-place Control) Written In Erlang C++
  • 9. Example: Tickets { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100123, "day": 20100123, "day": 20100123, "checkout": 100 "checkout": 42 "checkout": 215 "checkout": 73 } } } }
  • 10. Sum(checkout)? { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100123, "day": 20100123, "day": 20100123, "checkout": 100 "checkout": 42 "checkout": 215 "checkout": 73 } } } }
  • 11. Map: emit(checkout) 100 42 215 73 { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100123, "day": 20100123, "day": 20100123, "checkout": 100 "checkout": 42 "checkout": 215 "checkout": 73 } } } }
  • 12. Reduce: sum(checkouts) 142 288 100 42 215 73 { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100123, "day": 20100123, "day": 20100123, "checkout": 100 "checkout": 42 "checkout": 215 "checkout": 73 } } } }
  • 13. Reduce: sum(checkouts) 430 142 288 100 42 215 73 { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100123, "day": 20100123, "day": 20100123, "checkout": 100 "checkout": 42 "checkout": 215 "checkout": 73 } } } }
  • 14. Reduce must be associative reduce( 100 42 215 73 ) == 430 Must be equal to reduce( reduce( 100 42 ) == 142 reduce( 215 73 ) == 288 ) == 430
  • 16. Inherently distributed 430 142 288 100 42 215 73 { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100123, "day": 20100123, "day": 20100123, "checkout": 100 "checkout": 42 "checkout": 215 "checkout": 73 } } } }
  • 17. Logaritmic Update 430 142 288 100 42 215 73 { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100123, "day": 20100123, "day": 20100123, "checkout": 100 "checkout": 42 "checkout": 210 "checkout": 73 } } } }
  • 18. Logaritmic Update 430 142 288 100 42 210 73 { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100123, "day": 20100123, "day": 20100123, "checkout": 100 "checkout": 42 "checkout": 210 "checkout": 73 } } } }
  • 19. Logaritmic Update 430 142 283 100 42 210 73 { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100123, "day": 20100123, "day": 20100123, "checkout": 100 "checkout": 42 "checkout": 210 "checkout": 73 } } } }
  • 20. Logaritmic Update 425 142 283 100 42 210 73 { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100123, "day": 20100123, "day": 20100123, "checkout": 100 "checkout": 42 "checkout": 210 "checkout": 73 } } } }
  • 26. Sum(checkout) # START SERVER $ ~/opt/mongodb-1.3.0/bin/mongod --dbpath=./db/mongodb.01/ --logpath=./log/mongodb.01 --port 30001 # START SHELL $ ~/opt/mongodb-1.3.0/bin/mongo localhost:30001 connecting to: localhost:30001/test type "help" for help > show dbs admin local
  • 27. Sum(checkout) > use checkout switched to db checkout > db.tickets.save({ "_id": 1, "day": 20100123, "checkout": 100 }) > db.tickets.save({ "_id": 2, "day": 20100123, "checkout": 42 }) > db.tickets.save({ "_id": 3, "day": 20100123, "checkout": 215 }) > db.tickets.save({ "_id": 4, "day": 20100123, "checkout": 73 }) > db.tickets.count() 4 > db.tickets.find() { "_id" : 1, "day" : 20100123, "checkout" : 100 } ... > db.tickets.find({ "_id": 1 }) { "_id" : 1, "day" : 20100123, "checkout" : 100 }
  • 28. Sum(checkout) > var map = function() { ... emit(null, this.checkout) ... } > var reduce = function(key, values) { ... var sum = 0 ... for (var index in values) sum += values[index] ... return sum ... }
  • 29. Sum(checkout) Temporary Collection > sumOfCheckouts = db.tickets.mapReduce(map, reduce) { "result" : "tmp.mr.mapreduce_1263717818_4", "timeMillis" : 8, "counts" : { "input" : 4, "emit" : 4, "output" : 1 }, "ok" : 1 } > db.getCollectionNames() [ "tickets", "tmp.mr.mapreduce_1263717818_4", ] > db[sumOfCheckouts.result].find() { "_id" : null, "value" : 430 }
  • 30. Sum(checkout) Persistent Collection > db.tickets.mapReduce(map, reduce, { “out”: “sumOfCheckouts” }) > db.getCollectionNames() [ “sumOfCheckouts”, "tickets", "tmp.mr.mapreduce_1263717818_4" ] > db.sumOfCheckouts.find() { "_id" : null, "value" : 430 } > db.sumOfCheckouts.findOne().value 430
  • 31. Sum(checkout) Reduce by Group # GROUP AS MAP/REDUCE ALTERNATIVE > db.tickets.group({ ... "initial": { "sum": 0 }, ... "reduce": function(ticket, checkouts) { ...... checkouts.sum += ticket.checkout ...... } ... }) [ { "sum" : 430 } ]
  • 32. Sum(checkout) Group By day { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100124, "day": 20100123, "day": 20100124, "checkout": 100 "checkout": 42 "checkout": 215 "checkout": 73 } } } }
  • 33. Map: emit(day,checkout) “20100123”:100 “20100124”:42 “20100123”:215 “20100124”:73 { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100124, "day": 20100123, "day": 20100124, "checkout": 100 "checkout": 42 "checkout": 215 "checkout": 73 } } } }
  • 34. Reduce: sum(checkouts) “20100123”:315 “20100123”:100 “20100124”:42 “20100123”:215 “20100124”:73 { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100124, "day": 20100123, "day": 20100124, "checkout": 100 "checkout": 42 "checkout": 215 "checkout": 73 } } } }
  • 35. Reduce: sum(checkouts) “20100123”:315 “20100124”:115 “20100123”:100 “20100124”:42 “20100123”:215 “20100124”:73 { { { { "id": 1, "id": 2, "id": 3, "id": 4, "day": 20100123, "day": 20100124, "day": 20100123, "day": 20100124, "checkout": 100 "checkout": 42 "checkout": 215 "checkout": 73 } } } }
  • 38. Design Documents are Documents
  • 39. Design Documents are Documents
  • 43. Structured Keys and Group Levels
  • 44. Structured Keys and Group Levels
  • 45. Structured Keys and Group Levels
  • 46. Structured Keys and Group Levels
  • 47. Structured Keys and Group Levels
  • 48. Structured Keys and Group Levels
  • 49. Structured Keys and Group Levels
  • 50. Sum(Checkout) by day Update In-Place > db.tickets.update({ "_id": 1 }, { ... $set: { "products": { ...... "apple": { "quantity": 5, "price": 10 }, ...... "kiwi": { "quantity": 2, "price": 25 } ...... } ... }, ... $unset: { "checkout": 1 } ... }) > db.tickets.find() { "_id" : 1, "day" : 20100123, "products" : { "apple" : { "quantity" : 5, "price" : 10 }, "kiwi" : { "quantity" : 2, "price" : 25 } }} { "_id" : 2, "day" : 20100123, "checkout" : 42 } { "_id" : 3, "day" : 20100123, "checkout" : 215 } { "_id" : 4, "day" : 20100123, "checkout" : 73 }
  • 51. Sum(Checkout) by day Calculate Checkout > db.tickets.find() { "_id" : 1, "day" : 20100123, "products" : { "apple" : { "quantity" : 5, "price" : 10 }, "kiwi" : { "quantity" : 2, "price" : 25 } } } { "_id" : 2, "day" : 20100124, "products" : { "banana" : { "quantity" : 2, "price" : 20 } } } { "_id" : 3, "day" : 20100123, "products" : { "kiwi" : { "quantity" : 4, "price" : 25 }, "babana" : { "quantity" : 5, "price" : 20 }, "lemon" : { "quantity" : 3, "price" : 5 } } } { "_id" : 4, "day" : 20100124, "products" : { "kiwi" : { "quantity" : 2, "price" : 25 }, "babana" : { "quantity" : 1, "price" : 20 } } }
  • 52. Sum(Checkout) by day Calculate Checkout > var map = function() { ... var checkout = 0 ... for (var name in this.products) { ...... var product = this.products[name] ...... checkout += product.quantity * product.price ...... } ... emit(this.day, checkout) } > var reduce = function(key, values) { ... var sum = 0 ... for (var index in values) sum += values[index] ... return sum }
  • 53. Sum(Checkout) by day Calculate Checkout > db.tickets.mapReduce(map, reduce, { "out": "sumOfCheckouts" }) > db.sumOfCheckouts.find() { "_id" : 20100123, "value" : 315 } { "_id" : 20100124, "value" : 110 }
  • 54. Sum(Checkout) by day Data Normalization > db.tickets.find() { "_id" : 1, "day" : 20100123, "products" : { "apple" : 5, "kiwi" : 2 } } { "_id" : 2, "day" : 20100124, "products" : { "banana" : 2 } } { "_id" : 3, "day" : 20100123, "products" : { "kiwi" : 4, "banana" : 5, "lemon" : 3 } } { "_id" : 4, "day" : 20100124, "products" : { "kiwi" : 2, "banana" : 1 } } > db.product.find() { "_id" : "apple", "price" : 10 } { "_id" : "kiwi", "price" : 25 } { "_id" : "banana", "price" : 20 } { "_id" : "lemon", "price" : 5 }
  • 55. Sum(Checkout) by day Data Normalization > var map = function() { ... var checkout = 0 ... for (var name in this.products) { ...... var quantity = this.products[name] ...... var price = db.product.findOne({ "_id": name }).price ...... checkout += quantity * price ...... } ... emit(this.day, checkout) } > var reduce = function(key, values) { ... var sum = 0 ... for (var index in values) sum += values[index] ... return sum }
  • 56. Sum(Checkout) by day Data Normalization > db.tickets.mapReduce(map, reduce, { "out": "sumOfCheckouts" }) > db.sumOfCheckouts.find() { "_id" : 20100123, "value" : 315 } { "_id" : 20100124, "value" : 110 }
  • 57. Count of unique elements? > db.view.find(); { "user" : "001", "page" : "example.com/001", "time" : 2 } { "user" : "001", "page" : "example.com/002", "time" : 4 } { "user" : "002", "page" : "example.com/001", "time" : 6 } { "user" : "002", "page" : "example.com/002", "time" : 10 } { "user" : "002", "page" : "example.com/002", "time" : 12 } { "user" : "002", "page" : "example.com/003", "time" : 1 } { "user" : "003", "page" : "example.com/001", "time" : 42 } { "user" : "003", "page" : "example.com/001", "time" : 9 } # USER NAVIGATION SURVEY = FOR EACH USER # NUMBER OF UNIQUE PAGES # AVERAGE TIME ON A PAGE
  • 58. Count of unique elements? > var map = function() { ... var accumulator = { ...... "numberOfViews": 1, ...... "visitedPages": {}, ...... "totalTime": 0 ...... }; ... accumulator["visitedPages"][this.page] = 1 ... accumulator["totalTime"] += this.time ... emit(this.user, accumulator) }
  • 59. Count of unique elements? # EASY TO DEBUG > var aUser = db.view.findOne({ "user": "001" }) > var emit = function(id, value) { print(tojson(value)) } > map.call(aUser) { "numberOfViews" : 1, "visitedPages" : { "example.com/001" : 1 }, "totalTime" : 2 }
  • 60. Count of unique elements? > var reduce = function(key, values) { ... var accumulator = { ...... "numberOfViews": 0, ...... "visitedPages": {}, ...... "totalTime": 0 ...... }; ... values.forEach(function(value) { ...... accumulator["numberOfViews"] += value["numberOfViews"] ...... accumulator["totalTime"] += value["totalTime"] ...... for (var page in value["visitedPages"]) { ......... if (accumulator["visitedPages"][page] === undefined) { ............ accumulator["visitedPages"][page] = 0 ......... } ......... accumulator["visitedPages"][page] += 1 ...... } ... }) ... return accumulator }
  • 61. Count of unique elements? > db.view.mapReduce(map, reduce, { "out": "userNavigationSurvey" }) # NOT AS WE WANTED > db.userNavigationSurvey.find() { "_id" : "001", "value" : { "numberOfViews" : 2, "visitedPages" : { "example.com/001" : 1, "example.com/002" : 1 }, "totalTime" : 6 } } { "_id" : "002", "value" : { "numberOfViews" : 4, "visitedPages" : { ...
  • 62. Count of unique elements? > var finalize = function(key, accumulator) { ... accumulator["averageTime"] = ...... accumulator["totalTime"] / accumulator["numberOfViews"] ... accumulator["numberOfUniquePages"] = 0 ... for (var page in accumulator["visitedPages"]) { ...... accumulator["numberOfUniquePages"] += 1 ... } ... delete accumulator["totalTime"] ... delete accumulator["numberOfViews"] ... delete accumulator["visitedPages"] ... return accumulator }
  • 63. Count of unique elements? > db.view.mapReduce(map, reduce, { ... "finalize": finalize, ... "out": "userNavigationSurvey" }) > db.userNavigationSurvey.find() { "_id" : "001", "value" : { "averageTime" : 3, "numberOfUniquePages" : 2 } } { "_id" : "002", "value" : { "averageTime" : 7.25, "numberOfUniquePages" : 3 } } { "_id" : "003", "value" : { "averageTime" : 25.5, "numberOfUniquePages" : 1 } }
  • 65. Count of unique elements by steps # STEP 1: CREATE THE BASE COLLECTION (WITHOUT UNIQUE ELEMENTS) > var mapBase = function() { ... emit(this.user, { ...... "numberOfViews": 1, ...... "totalTime": this.time ... }) } > var reduceBase = function(key, values) { ... var accumulator = { ...... "numberOfViews": 0, ...... "totalTime": 0 ... }; ... values.forEach(function(value) { ...... accumulator["numberOfViews"] += value["numberOfViews"] ...... accumulator["totalTime"] += value["totalTime"] ... }) ... return accumulator }
  • 66. Count of unique elements by steps > var finalizeBase = function(key, accumulator) { ... accumulator["numberOfUniquePages"] = 0 ... accumulator["averageTime"] = ...... accumulator["totalTime"] / accumulator["numberOfViews"] ... delete accumulator["totalTime"] ... delete accumulator["numberOfViews"] ... return accumulator } > db.view.mapReduce(mapBase, reduceBase, { "finalize": finalizeBase, "out": "userNavigationSurvey" }) > db.userNavigationSurvey.find() { "_id" : "001", "value" : { "numberOfUniquePages" : 0, "averageTime" : 3 } } { "_id" : "002", "value" : { "numberOfUniquePages" : 0, "averageTime" : 7.25 } } { "_id" : "003", "value" : { "numberOfUniquePages" : 0, "averageTime" : 25.5 } }
  • 67. Count of unique elements by steps # STEP 2: CREATE THE COLLECTION OF UNIQUE ELEMENTS > var mapUniquePages = function() { ... emit(this.user + "-" + this.page, { ...... "user": this.user, ...... "page": this.page ... }) } > var reduceUniquePages = function(key, values) { ... return values[0] } > db.view.mapReduce(mapUniquePages, reduceUniquePages { "out": "userUniquePages" })
  • 68. Count of unique elements by steps > db.userUniquePages.find() { "_id" : "001-example.com/001", "value" : { "user" : "001", "page" : "example.com/001" } } { "_id" : "001-example.com/002", "value" : { "user" : "001", "page" : "example.com/002" } } { "_id" : "002-example.com/001", "value" : { "user" : "002", "page" : "example.com/001" } } { "_id" : "002-example.com/002", "value" : { "user" : "002", "page" : "example.com/002" } } { "_id" : "002-example.com/003", "value" : { "user" : "002", "page" : "example.com/003" } } { "_id" : "003-example.com/001", "value" : { "user" : "003", "page" : "example.com/001" } }
  • 69. Count of unique elements by steps # STEP 3: UPDATE BASE COLLECTION WITH UNIQUE ELEMENTS COUNT > db.userUniquePages.find().forEach(function(userUniquePage) { db.userNavigationSurvey.update( { "_id": userUniquePage.value.user }, { $inc: { "value.numberOfUniquePages": 1 } } ) }) > db.userNavigationSurvey.find() { "_id" : "001", "value" : { "numberOfUniquePages" : 2, "averageTime" : 3 } } { "_id" : "002", "value" : { "numberOfUniquePages" : 3, "averageTime" : 7.25 } } { "_id" : "003", "value" : { "numberOfUniquePages" : 1, "averageTime" : 25.5 } }
  • 70. Architecture Webmachine HTTP HTTP HTTP
  • 71. Scalability Webmachine Nginx Master/Master Webmachine
  • 74. Received by <account> After <timestamp>? function(document) { if (document.from && document.to) { var key = [ document.to, document.timestamp ] var content = document._attachments["content"] var outline = { "id": document._id, "from": document.from, "timestamp": document.timestamp, "type": content["content_type"], "length": content["length"], } emit(key, outline) } }
  • 75. Received by <account> After <timestamp>?
  • 76. Received by <account> After <timestamp>? > curl -X GET ".../mercurio/_design/message/_view/received_after" { "total_rows":3, "offset":0, "rows": [ { "id": "ff35356344ee0e9928c212b52e36e6f3", "key": [ "gabriele", 1263655442 ], "value": { "id": "ff35356344ee0e9928c212b52e36e6f3", "from": "chiara", "timestamp": 1263655442, "type": "text/plain;charset=utf-8", "length": 16 } }, ... }
  • 77. Results are ordered by Key { "key": [ "chiara", 126 ], "value": { "id": "ff35356344ee0e992...", "from": "gabriele" [ "chiara", 126 ] } == < } { "key": [ "chiara", 128 ], "value": { "id": "0deff99666425bacc...", [ "chiara", 128 ] "from": "gabriele" } < } { "key": [ "gabriele", 120 ], "value": { "id": "9842063609746c661...", [ "gabriele", 120 ] "from": "chiara" } }
  • 78. Select with Key { "key": [ "chiara", 126 ], "value": { "id": "ff35356344ee0e992...", received_after? } "from": "gabriele" key=["chiara",126] } { "key": [ "chiara", 128 ], "value": { "id": "0deff99666425bacc...", "from": "gabriele" } } { "key": [ "gabriele", 120 ], "value": { "id": "9842063609746c661...", "from": "chiara" } }
  • 79. Select with range of Keys { "key": [ "chiara", 126 ], received_after? "value": { "id": "ff35356344ee0e992...", "from": "gabriele" startkey=["chiara",126]& } } endkey=["gabriele",0] { "key": [ "chiara", 128 ], "value": { "id": "0deff99666425bacc...", "from": "gabriele" } } { "key": [ "gabriele", 120 ], "value": { "id": "9842063609746c661...", "from": "chiara" } }
  • 80. Select with range of Keys { "key": [ "chiara", 126 ], "value": { "id": "ff35356344ee0e992...", "from": "gabriele" } } [ "chiara", [] ] { "key": [ "chiara", 128 ], "value": { "id": "0deff99666425bacc...", "from": "gabriele" } { "key": [ "chiara", [] ], } "value": { "id": "0deff99666425bacc...", "from": "gabriele" { "key": [ "gabriele", 120 ], } "value": { } "id": "9842063609746c661...", "from": "chiara" } }
  • 81. Select with range of Keys { "key": [ "chiara", 126 ], received_after? "value": { "id": "ff35356344ee0e992...", "from": "gabriele" startkey=["chiara",126]& } } endkey=["chiara",[]] { "key": [ "chiara", 128 ], "value": { "id": "0deff99666425bacc...", "from": "gabriele" } } { "key": [ "gabriele", 120 ], "value": { "id": "9842063609746c661...", "from": "chiara" } }
  • 82. Received by “chiara” After 126 { "key": [ "chiara", 126 ], received_after? "value": { "id": "ff35356344ee0e992...", "from": "gabriele" startkey=["chiara",127]& } } endkey=["chiara",[]] { "key": [ "chiara", 128 ], "value": { "id": "0deff99666425bacc...", "from": "gabriele" } } { "key": [ "gabriele", 120 ], "value": { "id": "9842063609746c661...", "from": "chiara" } }
  • 83. Push Received Messages from Server Check for Messages _changes? received by <account.id> filter=message/received& after <timestamp> by=<account.id>& after=<timestamp> Send Message Save Document to <account.id> to: <account.id>
  • 84. Push Received Messages from Server _changes?filter=message/received&by=<account.id>&after=<timestamp> function(document, request) { var receivedByMe = document.to === request.query.by var receivedAfterLastTime = document.receivedAt >= request.query.after return receivedByMe && receivedAfterLastTime }