SlideShare a Scribd company logo
# M D B l o c a l
Aly Cabral, Product Manager
Using Change Streams to
Keep Up With Your Data
# M D B l o c a l
Alyson Cabral
PRODUCT MANAGER | MONGODB | @ ALY_CABRAL
# M D B l o c a l
“TIME IS MONEY.”
B E N J A M I N F R A N K L I N
WA R R E N B U F F E T
# M D B l o c a l
REAL-TIME IS AN EXPECTATION
@ A LY_C A B R A L
# M D B l o c a l
MongoDB
Action
Handler
@ A LY_C A B R A L
# M D B l o c a l
const changeStream=
db.collection(‘temperature’).watch();
c h a n g e S t r e a m . o n ( ' c h a n g e ' , f u n c t i o n ( c h a n g e ) {
c o n s o l e . l o g ( c h a n g e ) ;
} ) ;
@ A LY_C A B R A L
# M D B l o c a l
CHANGE STREAM
CHARACTERISTICS
# M D B l o c a l
5 OPERATION TYPES
INSERT
DELETE
REPLACE
UPDATE
INVALIDATE
@ A LY_C A B R A L
# M D B l o c a l
CHANGE STREAMS UTILIZE
COLLECTION ACCESS CONTROLS,
PRESENT A DEFINED API, AND ENABLE
SCALING ACROSS PRIMARIES AND
SECONDARIES.
@ A LY_C A B R A L
# M D B l o c a l
TOTAL ORDERING OF CHANGES ACROSS
SHARDS
mongos
3 1
2
Shard 1 Shard 2 Shard 3
@ A LY_C A B R A L
# M D B l o c a l
PS
CHANGES ARE DURABLE
P
S
@ A LY_C A B R A L
# M D B l o c a l
SP
CHANGE STREAMS ARE RESUMABLE
P
S
{_id: <resumeToken>,
operationType: ‘update’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘room12345’},
updateDescription: {updatedFields: {temperature: 70},
removedFields: [‘humidity’]}
}
var newChangeStream = coll.watch({ resumeAfter: <cachedResumeToken> });
@ A LY_C A B R A L
# M D B l o c a l
CHANGE STREAMS UTILIZE THE POWER
OF THE AGGREGATION FRAMEWORK
$match $project $addFields $replaceRoot $redact
var changeStream = coll.watch([{ $match: {$or: [{operationType: 'delete' }, {operationType:'replace'}]}}]);
@ A LY_C A B R A L
# M D B l o c a l
1. COLLECTION ACCESS CONTROLS
2. DEFINED API
3. ENABLE SCALING
4. TOTAL ORDERING
5. DURABLE
6. RESUMABLE
7. POWER OF AGGREGATION
@ A LY_C A B R A L
# M D B l o c a l
OPERATION TYPES
# M D B l o c a l
5 OPERATION TYPES
{ _id: (resumeToken),
operationType: ‘insert’,
ns: {db: ‘test’, coll: ‘foo’},
documentKey: {userName: ‘alice123’,
_id: ObjectId("58a4eb4a30c75625e00d2820")
},
fullDocument: {_id: ObjectId("58a4eb4a30c75625e00d2820"),
userName: ‘alice123’,
name: ‘Alice’
}
}
@ A LY_C A B R A L
INSERT
# M D B l o c a l
5 OPERATION TYPES
{_id: (resumeToken),
operationType: ‘delete’,
ns: {db: ‘test’, coll: ‘foo’},
documentKey: {userName: ‘alice123’,
_id: ObjectId("58a4eb4a30c75625e00d2820")
}
}
@ A LY_C A B R A L
DELETE
# M D B l o c a l
5 OPERATION
TYPES
@ A LY_C A B R A L
{_id: (resumeToken),
operationType: ‘replace’,
ns: {db: ‘test’, coll: ‘foo’},
documentKey: {userName: ‘alice123’,
_id: ObjectId("58a4eb4a30c75625e00d2820")
},
fullDocument: {_id: ObjectId("58a4eb4a30c75625e00d2820"),
userName: ‘alice123’,
name: ‘Alice’
}
}
REPLACE
# M D B l o c a l
UPDATE5 OPERATION TYPES
@ A LY_C A B R A L
{_id: (resumeToken),
operationType: ‘update’,
ns: {db: ‘test’, coll: ‘foo’},
documentKey: {userName: ‘alice123’,
_id: ObjectId("58a4eb4a30c75625e00d2820")
},
updateDescription: {updatedFields: {email: ‘alice@10gen.com’},
removedFields: [‘phoneNumber’]}
}
# M D B l o c a l
5 OPERATION
TYPES
{_id: (resumeToken),
operationType: ‘invalidate’,
ns: {db: ‘test’, coll: ‘foo’}}
@ A LY_C A B R A L
INVALIDATE
# M D B l o c a l
{_id: (resumeToken),
operationType: ‘update’,
ns: {db: ‘test’, coll: ‘foo’},
documentKey: {userName: ‘alice123’,
_id: ObjectId("58a4eb4a30c75625e00d2820")},
updateDescription: {updatedFields: {email: ‘alice@10gen.com’},
removedFields: [‘phoneNumber’]}
}
UPDATE
var changeStream = coll.watch({ fullDocument: 'updateLookup' });
@ A LY_C A B R A L
# M D B l o c a l
var changeStream = coll.watch({ fullDocument: 'updateLookup' });
UPDATE fullDocument: updateLookup
{_id: (resumeToken),
operationType: ‘update’,
ns: {db: ‘test’, coll: ‘foo’},
documentKey: {userName: ‘alice123’,
_id: ObjectId("58a4eb4a30c75625e00d2820")},
updateDescription: {updatedFields: {email:
‘alice@10gen.com’},
removedFields: [‘phoneNumber’]},
fullDocument: { _id: ObjectId("58a4eb4a30c75625e00d2820"),
name: ‘Alice’,
userName: ‘alice123’,
email: ‘alice@10gen.com’,
team: ‘replication’}
}
@ A LY_C A B R A L
# M D B l o c a l
1 . S H A R D K E Y I S U S E D ( B Y T H E M O N G O S ) TO R O U T E
O P E R AT I O N S
2 . _ I D U N I Q U E N E S S I S E N F O R C E D B Y S H A R D
mongos
3 1
2
Shard 1 Shard 2 Shard 3
DEFINING THE documentKey
@ A LY_C A B R A L
# M D B l o c a l
BACK TO
THE USE CASE
# M D B l o c a l@ A LY_C A B R A L
# M D B l o c a l
Action Handler
{_id: (resumeToken),
operationType: ‘insert’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘greenRoom123’},
fullDocument: {_id: ‘greenRoom123’),
temperature: 75,
username: aly_cabral}
}
var changeStream = coll.watch([{
$match: {{ 'fullDocument.temperature': {$gte : 70 }}},
{fullDocument: 'updateLookup' }]);
@ A LY_C A B R A L
# M D B l o c a l
{_id: (resumeToken),
operationType: ‘insert’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘orangeRoom123’
fullDocument: {_id: ‘orangeRoom123’,
temperature: 76,
username: eliot_horowitz }
}
Action Handler
var changeStream = coll.watch([{
$match: {{ 'fullDocument.temperature': {$gte : 70 }}},
{fullDocument: 'updateLookup' }]);
temperature: 75
username: aly_cabral
@ A LY_C A B R A L
# M D B l o c a l
Action Handler
{_id: (resumeToken),
operationType: ‘update’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘greenRoom123’)},
updateDescription: {updatedFields: {temperature: 68}
fullDocument: {_id: ‘greenRoom123’,
temperature: 68,
username: aly_cabral}
}
var changeStream = coll.watch([{
$match: {{ 'fullDocument.temperature': {$gte : 70 }}},
{fullDocument: 'updateLookup' }]);
temperature: 75
username: aly_cabral
@ A LY_C A B R A L
# M D B l o c a l
IF YOUR APPLICATION REQUIRES STATE
ALWAYS MATCH ON UNCHANGING
FIELDS
@ A LY_C A B R A L
# M D B l o c a l
Action Handler
var changeStream = coll.watch([{ $match: {{ 'fullDocument.username': ‘aly_cabral’ }}},
{fullDocument: 'updateLookup' }]);
temperature: 75
username: aly_cabral
{_id: (resumeToken),
operationType: ‘insert’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘blueRoom123’},
fullDocument: {_id: ‘blueRoom123’,
temperature: 85,
username: aly_cabral}
}
@ A LY_C A B R A L
# M D B l o c a l
Action Handler
var changeStream = coll.watch([{ $match: {{ 'fullDocument.username': ‘aly_cabral’ }}},
{fullDocument: 'updateLookup' }]);
temperature: 75
username: aly_cabral
temperature: 85
username: aly_cabral
{_id: (resumeToken),
operationType: ‘delete’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘blueRoom123’}}
@ A LY_C A B R A L
# M D B l o c a l
Action Handler
{_id: (resumeToken),
operationType: ‘replace’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘blueRoom123’},
fullDocument: {_id: ‘blueRoom123’,
temperature: 71,
username: asya_kamsky}
}
var changeStream = coll.watch([{ $match: {{ 'fullDocument.username': ‘aly_cabral’ }}},
{fullDocument: 'updateLookup' }]);
temperature: 75
username: aly_cabral
temperature: 85
username: aly_cabral
@ A LY_C A B R A L
# M D B l o c a l
IF YOUR APPLICATION NEEDS TO NOTIFY ON DELETED
DATA
ALWAYS HANDLE DELETES AND
REPLACES APPROPRIATELY
@ A LY_C A B R A L
# M D B l o c a l
var changeStream = coll.watch([{ $match: {
{ $or: [ { 'fullDocument.username': ‘aly_cabral'
}, { operationType: 'delete' },
{ operationType: 'replace' }]}],
{fullDocument: 'updateLookup' });
Insert
@ A LY_C A B R A L
# M D B l o c a l
var changeStream = coll.watch([{ $match: {
{ $or: [ { 'fullDocument.username': ‘aly_cabral'
}, { operationType: 'delete' },
{ operationType: 'replace' }]}],
{fullDocument: 'updateLookup' });
Insert Update
@ A LY_C A B R A L
# M D B l o c a l
var changeStream = coll.watch([{ $match: {
{ $or: [ { 'fullDocument.username': ‘aly_cabral'
}, { operationType: 'delete' },
{ operationType: 'replace' }]}],
{fullDocument: 'updateLookup' });
Insert Update Delete
@ A LY_C A B R A L
# M D B l o c a l
var changeStream = coll.watch([{ $match: {
{ $or: [ { 'fullDocument.username': ‘aly_cabral'
}, { operationType: 'delete' },
{ operationType: 'replace' }]}],
{fullDocument: 'updateLookup' });
Insert Update Delete
In the update notification fullDocument: null
updateLookup
@ A LY_C A B R A L
# M D B l o c a l
var changeStream = coll.watch([{ $match: {
{ $or: [ { 'fullDocument.username': ‘aly_cabral'
}, { operationType: 'delete' },
{ operationType: 'replace' }]}],
{fullDocument: 'updateLookup' });
Insert Update Delete
In the update notification fullDocument: null
updateLookup
{_id: (resumeToken),
operationType: ‘update’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {userName: ‘greenRoom123’},
updateDescription: {updatedFields: {temperature: 78}},
fullDocument: {}
}
@ A LY_C A B R A L
# M D B l o c a l
IF YOU NEED TO SEE EVERY CHANGE (EVEN OUTDATED
CHANGES) TO A DOCUMENT
HAVE MATCHING FIELDS IN THE
DOCUMENT KEY
@ A LY_C A B R A L
# M D B l o c a l
{_id: (resumeToken),
operationType: ‘insert’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘blueRoom123’,
username: “aly_cabral”},
fullDocument: {_id: ‘blueRoom123’,
temperature: 85,
username: “aly_cabral”}
}
Action Handler
var changeStream = coll.watch([{ $match: {{ ‘documentKey.username’: ‘aly_cabral’ }}},
{fullDocument: 'updateLookup' }]);
temperature: 75
username: aly_cabral
@ A LY_C A B R A L
# M D B l o c a l
Action Handler
var changeStream = coll.watch([{ $match: {{ ‘documentKey.username’: ‘aly_cabral’ }}},
{fullDocument: 'updateLookup' }]);
temperature: 75
username: aly_cabral
temperature: 85
username: aly_cabral
{_id: (resumeToken),
operationType: ‘delete’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘blueRoom123’,
username: “aly_cabral”)}}
@ A LY_C A B R A L
# M D B l o c a l
{_id: (resumeToken),
operationType: ‘insert’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘blueRoom123’,
username: “aly_cabral”},
fullDocument: {_id: ‘blueRoom123’,
temperature: 85,
username: “aly_cabral”}
}
Action Handler
var changeStream = coll.watch([{ $match: {{ ‘documentKey.username’: ‘aly_cabral’ }}},
{fullDocument: 'updateLookup' }]);
temperature: 75
username: aly_cabral
temperature: 85
username: aly_cabral
{_id: (resumeToken),
operationType: ‘delete’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘blueRoom123’,
username: “aly_cabral”)}}
{_id: (resumeToken),
operationType: ‘replace’,
ns: {db: ‘data’, coll: ‘temperature’},
documentKey: {_id: ‘greenRoom123’,
username: ‘aly_cabral’},
fullDocument: {_id: ‘greenRoom123’,
temperature: 71,
username: “asya_kamsky”}
}
@ A LY_C A B R A L
# M D B l o c a l
UNDERLYING
TECHNOLOGY
# M D B l o c a l
P
S
S
S
S
@ A LY_C A B R A L
# M D B l o c a l
123456
@ A LY_C A B R A L
# M D B l o c a l
RESUMABLE
304 270 233 208 201 190
C A C H E D R E S U M E TO K E N : 2 0 8
N E W E S T O L D E S T
D E L E T E D
@ A LY_C A B R A L
# M D B l o c a l
304 270 233 208 201 190
C A C H E D R E S U M E TO K E N : 1 9 0
N E W E S T O L D E S T
D E L E T E D
NON-RESUMABLE
@ A LY_C A B R A L
# M D B l o c a l
YOU MADE IT!
@ A LY_C A B R A L

More Related Content

PPTX
Insight on MongoDB Change Stream - Abhishek.D, Mydbops Team
PPTX
Databricks Fundamentals
PDF
Mongo db dhruba
PDF
Optimizing S3 Write-heavy Spark workloads
PPTX
Apache spark architecture (Big Data and Analytics)
PDF
Microsoft Azure Storage Overview | Microsoft Azure Training | Microsoft Azure...
PDF
Introduction to Azure Data Factory
PPTX
Large Scale Graph Analytics with JanusGraph
Insight on MongoDB Change Stream - Abhishek.D, Mydbops Team
Databricks Fundamentals
Mongo db dhruba
Optimizing S3 Write-heavy Spark workloads
Apache spark architecture (Big Data and Analytics)
Microsoft Azure Storage Overview | Microsoft Azure Training | Microsoft Azure...
Introduction to Azure Data Factory
Large Scale Graph Analytics with JanusGraph

What's hot (20)

PDF
NoSQL Essentials: Cassandra
PPTX
Evolution of Big Data Messaging
PDF
Introduction to MLflow
PDF
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3
PDF
The Neo4j Data Platform for Today & Tomorrow.pdf
PDF
Apache spark
PDF
Introduction to Spark with Python
PPTX
PPTX
Graphs for Genealogists
PDF
Building an ML Platform with Ray and MLflow
PDF
Dependency Injection in Apache Spark Applications
PDF
[232] TensorRT를 활용한 딥러닝 Inference 최적화
PDF
Netflix Architecture Tutorial at Gluecon
PPTX
Role-Based Access Control (RBAC) in Neo4j
PDF
Amazon S3 Best Practice and Tuning for Hadoop/Spark in the Cloud
PDF
Oracle APEX勉強会 - 認証と認可の実装を学ぶ
PDF
Diving into Delta Lake: Unpacking the Transaction Log
PPTX
Introducing Azure SQL Data Warehouse
PDF
Spark on Kubernetes
PDF
The Parquet Format and Performance Optimization Opportunities
NoSQL Essentials: Cassandra
Evolution of Big Data Messaging
Introduction to MLflow
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3
The Neo4j Data Platform for Today & Tomorrow.pdf
Apache spark
Introduction to Spark with Python
Graphs for Genealogists
Building an ML Platform with Ray and MLflow
Dependency Injection in Apache Spark Applications
[232] TensorRT를 활용한 딥러닝 Inference 최적화
Netflix Architecture Tutorial at Gluecon
Role-Based Access Control (RBAC) in Neo4j
Amazon S3 Best Practice and Tuning for Hadoop/Spark in the Cloud
Oracle APEX勉強会 - 認証と認可の実装を学ぶ
Diving into Delta Lake: Unpacking the Transaction Log
Introducing Azure SQL Data Warehouse
Spark on Kubernetes
The Parquet Format and Performance Optimization Opportunities
Ad

Similar to Using Change Streams to Keep Up with Your Data (20)

PPTX
Using Change Streams to Keep Up with Your Data
PPTX
SH 1 - SES 7 - Change-Streams-Tel-Aviv.pptx
PPTX
Using Change Streams to Keep Up with Your Data
PPTX
Using Change Streams to Keep Up with Your Data
PPTX
[MongoDB.local Bengaluru 2018] Using Change Streams to Keep Up With Your Data
PDF
Function Procedure Trigger Partition.pdf
PDF
MongoDB World 2018: Using Change Streams to Keep Up with Your Data
PPT
Dynamically Evolving Systems: Cluster Analysis Using Time
PPT
Oracle database - Get external data via HTTP, FTP and Web Services
PDF
Graphql, REST and Apollo
PDF
Classic Games Development with Drools
PDF
Angular Promises and Advanced Routing
DOCX
Pratik Bakane C++
KEY
Grails UI Primer
PDF
Inversion Of Control
PDF
Redux for ReactJS Programmers
PPTX
SH 1 - SES 3 - 3.6-Overview-Tel-Aviv.pptx
PPTX
SH 1 - SES 3 - 3.6-Overview-Tel-Aviv.pptx
PDF
ITB2019 10 in 50: Ten Coldbox Modules You Should be Using in Every App - Jon ...
PDF
2018 02-22 React, Redux & Building Applications that Scale | Redux
Using Change Streams to Keep Up with Your Data
SH 1 - SES 7 - Change-Streams-Tel-Aviv.pptx
Using Change Streams to Keep Up with Your Data
Using Change Streams to Keep Up with Your Data
[MongoDB.local Bengaluru 2018] Using Change Streams to Keep Up With Your Data
Function Procedure Trigger Partition.pdf
MongoDB World 2018: Using Change Streams to Keep Up with Your Data
Dynamically Evolving Systems: Cluster Analysis Using Time
Oracle database - Get external data via HTTP, FTP and Web Services
Graphql, REST and Apollo
Classic Games Development with Drools
Angular Promises and Advanced Routing
Pratik Bakane C++
Grails UI Primer
Inversion Of Control
Redux for ReactJS Programmers
SH 1 - SES 3 - 3.6-Overview-Tel-Aviv.pptx
SH 1 - SES 3 - 3.6-Overview-Tel-Aviv.pptx
ITB2019 10 in 50: Ten Coldbox Modules You Should be Using in Every App - Jon ...
2018 02-22 React, Redux & Building Applications that Scale | Redux
Ad

More from MongoDB (20)

PDF
MongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
PDF
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
PDF
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
PDF
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
PDF
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
PDF
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
PDF
MongoDB SoCal 2020: MongoDB Atlas Jump Start
PDF
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
PDF
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
PDF
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
PDF
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
PDF
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
PDF
MongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
PDF
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
PDF
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
PDF
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
PDF
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
PDF
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
PDF
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
PDF
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...
MongoDB SoCal 2020: Migrate Anything* to MongoDB Atlas
MongoDB SoCal 2020: Go on a Data Safari with MongoDB Charts!
MongoDB SoCal 2020: Using MongoDB Services in Kubernetes: Any Platform, Devel...
MongoDB SoCal 2020: A Complete Methodology of Data Modeling for MongoDB
MongoDB SoCal 2020: From Pharmacist to Analyst: Leveraging MongoDB for Real-T...
MongoDB SoCal 2020: Best Practices for Working with IoT and Time-series Data
MongoDB SoCal 2020: MongoDB Atlas Jump Start
MongoDB .local San Francisco 2020: Powering the new age data demands [Infosys]
MongoDB .local San Francisco 2020: Using Client Side Encryption in MongoDB 4.2
MongoDB .local San Francisco 2020: Using MongoDB Services in Kubernetes: any ...
MongoDB .local San Francisco 2020: Go on a Data Safari with MongoDB Charts!
MongoDB .local San Francisco 2020: From SQL to NoSQL -- Changing Your Mindset
MongoDB .local San Francisco 2020: MongoDB Atlas Jumpstart
MongoDB .local San Francisco 2020: Tips and Tricks++ for Querying and Indexin...
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: A Complete Methodology of Data Modeling fo...
MongoDB .local San Francisco 2020: MongoDB Atlas Data Lake Technical Deep Dive
MongoDB .local San Francisco 2020: Developing Alexa Skills with MongoDB & Golang
MongoDB .local Paris 2020: Realm : l'ingrédient secret pour de meilleures app...
MongoDB .local Paris 2020: Upply @MongoDB : Upply : Quand le Machine Learning...

Using Change Streams to Keep Up with Your Data

  • 1. # M D B l o c a l Aly Cabral, Product Manager Using Change Streams to Keep Up With Your Data
  • 2. # M D B l o c a l Alyson Cabral PRODUCT MANAGER | MONGODB | @ ALY_CABRAL
  • 3. # M D B l o c a l “TIME IS MONEY.” B E N J A M I N F R A N K L I N WA R R E N B U F F E T
  • 4. # M D B l o c a l REAL-TIME IS AN EXPECTATION @ A LY_C A B R A L
  • 5. # M D B l o c a l MongoDB Action Handler @ A LY_C A B R A L
  • 6. # M D B l o c a l const changeStream= db.collection(‘temperature’).watch(); c h a n g e S t r e a m . o n ( ' c h a n g e ' , f u n c t i o n ( c h a n g e ) { c o n s o l e . l o g ( c h a n g e ) ; } ) ; @ A LY_C A B R A L
  • 7. # M D B l o c a l CHANGE STREAM CHARACTERISTICS
  • 8. # M D B l o c a l 5 OPERATION TYPES INSERT DELETE REPLACE UPDATE INVALIDATE @ A LY_C A B R A L
  • 9. # M D B l o c a l CHANGE STREAMS UTILIZE COLLECTION ACCESS CONTROLS, PRESENT A DEFINED API, AND ENABLE SCALING ACROSS PRIMARIES AND SECONDARIES. @ A LY_C A B R A L
  • 10. # M D B l o c a l TOTAL ORDERING OF CHANGES ACROSS SHARDS mongos 3 1 2 Shard 1 Shard 2 Shard 3 @ A LY_C A B R A L
  • 11. # M D B l o c a l PS CHANGES ARE DURABLE P S @ A LY_C A B R A L
  • 12. # M D B l o c a l SP CHANGE STREAMS ARE RESUMABLE P S {_id: <resumeToken>, operationType: ‘update’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘room12345’}, updateDescription: {updatedFields: {temperature: 70}, removedFields: [‘humidity’]} } var newChangeStream = coll.watch({ resumeAfter: <cachedResumeToken> }); @ A LY_C A B R A L
  • 13. # M D B l o c a l CHANGE STREAMS UTILIZE THE POWER OF THE AGGREGATION FRAMEWORK $match $project $addFields $replaceRoot $redact var changeStream = coll.watch([{ $match: {$or: [{operationType: 'delete' }, {operationType:'replace'}]}}]); @ A LY_C A B R A L
  • 14. # M D B l o c a l 1. COLLECTION ACCESS CONTROLS 2. DEFINED API 3. ENABLE SCALING 4. TOTAL ORDERING 5. DURABLE 6. RESUMABLE 7. POWER OF AGGREGATION @ A LY_C A B R A L
  • 15. # M D B l o c a l OPERATION TYPES
  • 16. # M D B l o c a l 5 OPERATION TYPES { _id: (resumeToken), operationType: ‘insert’, ns: {db: ‘test’, coll: ‘foo’}, documentKey: {userName: ‘alice123’, _id: ObjectId("58a4eb4a30c75625e00d2820") }, fullDocument: {_id: ObjectId("58a4eb4a30c75625e00d2820"), userName: ‘alice123’, name: ‘Alice’ } } @ A LY_C A B R A L INSERT
  • 17. # M D B l o c a l 5 OPERATION TYPES {_id: (resumeToken), operationType: ‘delete’, ns: {db: ‘test’, coll: ‘foo’}, documentKey: {userName: ‘alice123’, _id: ObjectId("58a4eb4a30c75625e00d2820") } } @ A LY_C A B R A L DELETE
  • 18. # M D B l o c a l 5 OPERATION TYPES @ A LY_C A B R A L {_id: (resumeToken), operationType: ‘replace’, ns: {db: ‘test’, coll: ‘foo’}, documentKey: {userName: ‘alice123’, _id: ObjectId("58a4eb4a30c75625e00d2820") }, fullDocument: {_id: ObjectId("58a4eb4a30c75625e00d2820"), userName: ‘alice123’, name: ‘Alice’ } } REPLACE
  • 19. # M D B l o c a l UPDATE5 OPERATION TYPES @ A LY_C A B R A L {_id: (resumeToken), operationType: ‘update’, ns: {db: ‘test’, coll: ‘foo’}, documentKey: {userName: ‘alice123’, _id: ObjectId("58a4eb4a30c75625e00d2820") }, updateDescription: {updatedFields: {email: ‘alice@10gen.com’}, removedFields: [‘phoneNumber’]} }
  • 20. # M D B l o c a l 5 OPERATION TYPES {_id: (resumeToken), operationType: ‘invalidate’, ns: {db: ‘test’, coll: ‘foo’}} @ A LY_C A B R A L INVALIDATE
  • 21. # M D B l o c a l {_id: (resumeToken), operationType: ‘update’, ns: {db: ‘test’, coll: ‘foo’}, documentKey: {userName: ‘alice123’, _id: ObjectId("58a4eb4a30c75625e00d2820")}, updateDescription: {updatedFields: {email: ‘alice@10gen.com’}, removedFields: [‘phoneNumber’]} } UPDATE var changeStream = coll.watch({ fullDocument: 'updateLookup' }); @ A LY_C A B R A L
  • 22. # M D B l o c a l var changeStream = coll.watch({ fullDocument: 'updateLookup' }); UPDATE fullDocument: updateLookup {_id: (resumeToken), operationType: ‘update’, ns: {db: ‘test’, coll: ‘foo’}, documentKey: {userName: ‘alice123’, _id: ObjectId("58a4eb4a30c75625e00d2820")}, updateDescription: {updatedFields: {email: ‘alice@10gen.com’}, removedFields: [‘phoneNumber’]}, fullDocument: { _id: ObjectId("58a4eb4a30c75625e00d2820"), name: ‘Alice’, userName: ‘alice123’, email: ‘alice@10gen.com’, team: ‘replication’} } @ A LY_C A B R A L
  • 23. # M D B l o c a l 1 . S H A R D K E Y I S U S E D ( B Y T H E M O N G O S ) TO R O U T E O P E R AT I O N S 2 . _ I D U N I Q U E N E S S I S E N F O R C E D B Y S H A R D mongos 3 1 2 Shard 1 Shard 2 Shard 3 DEFINING THE documentKey @ A LY_C A B R A L
  • 24. # M D B l o c a l BACK TO THE USE CASE
  • 25. # M D B l o c a l@ A LY_C A B R A L
  • 26. # M D B l o c a l Action Handler {_id: (resumeToken), operationType: ‘insert’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘greenRoom123’}, fullDocument: {_id: ‘greenRoom123’), temperature: 75, username: aly_cabral} } var changeStream = coll.watch([{ $match: {{ 'fullDocument.temperature': {$gte : 70 }}}, {fullDocument: 'updateLookup' }]); @ A LY_C A B R A L
  • 27. # M D B l o c a l {_id: (resumeToken), operationType: ‘insert’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘orangeRoom123’ fullDocument: {_id: ‘orangeRoom123’, temperature: 76, username: eliot_horowitz } } Action Handler var changeStream = coll.watch([{ $match: {{ 'fullDocument.temperature': {$gte : 70 }}}, {fullDocument: 'updateLookup' }]); temperature: 75 username: aly_cabral @ A LY_C A B R A L
  • 28. # M D B l o c a l Action Handler {_id: (resumeToken), operationType: ‘update’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘greenRoom123’)}, updateDescription: {updatedFields: {temperature: 68} fullDocument: {_id: ‘greenRoom123’, temperature: 68, username: aly_cabral} } var changeStream = coll.watch([{ $match: {{ 'fullDocument.temperature': {$gte : 70 }}}, {fullDocument: 'updateLookup' }]); temperature: 75 username: aly_cabral @ A LY_C A B R A L
  • 29. # M D B l o c a l IF YOUR APPLICATION REQUIRES STATE ALWAYS MATCH ON UNCHANGING FIELDS @ A LY_C A B R A L
  • 30. # M D B l o c a l Action Handler var changeStream = coll.watch([{ $match: {{ 'fullDocument.username': ‘aly_cabral’ }}}, {fullDocument: 'updateLookup' }]); temperature: 75 username: aly_cabral {_id: (resumeToken), operationType: ‘insert’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘blueRoom123’}, fullDocument: {_id: ‘blueRoom123’, temperature: 85, username: aly_cabral} } @ A LY_C A B R A L
  • 31. # M D B l o c a l Action Handler var changeStream = coll.watch([{ $match: {{ 'fullDocument.username': ‘aly_cabral’ }}}, {fullDocument: 'updateLookup' }]); temperature: 75 username: aly_cabral temperature: 85 username: aly_cabral {_id: (resumeToken), operationType: ‘delete’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘blueRoom123’}} @ A LY_C A B R A L
  • 32. # M D B l o c a l Action Handler {_id: (resumeToken), operationType: ‘replace’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘blueRoom123’}, fullDocument: {_id: ‘blueRoom123’, temperature: 71, username: asya_kamsky} } var changeStream = coll.watch([{ $match: {{ 'fullDocument.username': ‘aly_cabral’ }}}, {fullDocument: 'updateLookup' }]); temperature: 75 username: aly_cabral temperature: 85 username: aly_cabral @ A LY_C A B R A L
  • 33. # M D B l o c a l IF YOUR APPLICATION NEEDS TO NOTIFY ON DELETED DATA ALWAYS HANDLE DELETES AND REPLACES APPROPRIATELY @ A LY_C A B R A L
  • 34. # M D B l o c a l var changeStream = coll.watch([{ $match: { { $or: [ { 'fullDocument.username': ‘aly_cabral' }, { operationType: 'delete' }, { operationType: 'replace' }]}], {fullDocument: 'updateLookup' }); Insert @ A LY_C A B R A L
  • 35. # M D B l o c a l var changeStream = coll.watch([{ $match: { { $or: [ { 'fullDocument.username': ‘aly_cabral' }, { operationType: 'delete' }, { operationType: 'replace' }]}], {fullDocument: 'updateLookup' }); Insert Update @ A LY_C A B R A L
  • 36. # M D B l o c a l var changeStream = coll.watch([{ $match: { { $or: [ { 'fullDocument.username': ‘aly_cabral' }, { operationType: 'delete' }, { operationType: 'replace' }]}], {fullDocument: 'updateLookup' }); Insert Update Delete @ A LY_C A B R A L
  • 37. # M D B l o c a l var changeStream = coll.watch([{ $match: { { $or: [ { 'fullDocument.username': ‘aly_cabral' }, { operationType: 'delete' }, { operationType: 'replace' }]}], {fullDocument: 'updateLookup' }); Insert Update Delete In the update notification fullDocument: null updateLookup @ A LY_C A B R A L
  • 38. # M D B l o c a l var changeStream = coll.watch([{ $match: { { $or: [ { 'fullDocument.username': ‘aly_cabral' }, { operationType: 'delete' }, { operationType: 'replace' }]}], {fullDocument: 'updateLookup' }); Insert Update Delete In the update notification fullDocument: null updateLookup {_id: (resumeToken), operationType: ‘update’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {userName: ‘greenRoom123’}, updateDescription: {updatedFields: {temperature: 78}}, fullDocument: {} } @ A LY_C A B R A L
  • 39. # M D B l o c a l IF YOU NEED TO SEE EVERY CHANGE (EVEN OUTDATED CHANGES) TO A DOCUMENT HAVE MATCHING FIELDS IN THE DOCUMENT KEY @ A LY_C A B R A L
  • 40. # M D B l o c a l {_id: (resumeToken), operationType: ‘insert’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘blueRoom123’, username: “aly_cabral”}, fullDocument: {_id: ‘blueRoom123’, temperature: 85, username: “aly_cabral”} } Action Handler var changeStream = coll.watch([{ $match: {{ ‘documentKey.username’: ‘aly_cabral’ }}}, {fullDocument: 'updateLookup' }]); temperature: 75 username: aly_cabral @ A LY_C A B R A L
  • 41. # M D B l o c a l Action Handler var changeStream = coll.watch([{ $match: {{ ‘documentKey.username’: ‘aly_cabral’ }}}, {fullDocument: 'updateLookup' }]); temperature: 75 username: aly_cabral temperature: 85 username: aly_cabral {_id: (resumeToken), operationType: ‘delete’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘blueRoom123’, username: “aly_cabral”)}} @ A LY_C A B R A L
  • 42. # M D B l o c a l {_id: (resumeToken), operationType: ‘insert’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘blueRoom123’, username: “aly_cabral”}, fullDocument: {_id: ‘blueRoom123’, temperature: 85, username: “aly_cabral”} } Action Handler var changeStream = coll.watch([{ $match: {{ ‘documentKey.username’: ‘aly_cabral’ }}}, {fullDocument: 'updateLookup' }]); temperature: 75 username: aly_cabral temperature: 85 username: aly_cabral {_id: (resumeToken), operationType: ‘delete’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘blueRoom123’, username: “aly_cabral”)}} {_id: (resumeToken), operationType: ‘replace’, ns: {db: ‘data’, coll: ‘temperature’}, documentKey: {_id: ‘greenRoom123’, username: ‘aly_cabral’}, fullDocument: {_id: ‘greenRoom123’, temperature: 71, username: “asya_kamsky”} } @ A LY_C A B R A L
  • 43. # M D B l o c a l UNDERLYING TECHNOLOGY
  • 44. # M D B l o c a l P S S S S @ A LY_C A B R A L
  • 45. # M D B l o c a l 123456 @ A LY_C A B R A L
  • 46. # M D B l o c a l RESUMABLE 304 270 233 208 201 190 C A C H E D R E S U M E TO K E N : 2 0 8 N E W E S T O L D E S T D E L E T E D @ A LY_C A B R A L
  • 47. # M D B l o c a l 304 270 233 208 201 190 C A C H E D R E S U M E TO K E N : 1 9 0 N E W E S T O L D E S T D E L E T E D NON-RESUMABLE @ A LY_C A B R A L
  • 48. # M D B l o c a l YOU MADE IT! @ A LY_C A B R A L

Editor's Notes

  • #4: Before we get into the fun stuff, I have a little story. I was at a trivia night recently and one of the questions was who popularized the term “time is money”. My guess, naturally, was Warren Buffet as the was the famous business man the popped into my head at the time. Well, turns out I was only a couple centuries off. The real answer is Benjamin Franklin. Benjamin Franklin popularized the term time is money in the1700s. What a fascinating phrase it feels weirdly modern doesn’t it? I think it’s because this phrase has never rang more true than it is today. With the evolution of technology, and enabled by these innovations, each of us is able to do more and more in every second. We live in an era where we can catch up on the lastest news, socialize with our friends, get a date for the evening -- all in the two minutes it takes for us to use the restroom. While that is a silly example, we have become accustomed to doing and reacting to things as quickly as possible.
  • #5: As the builders we are in this room, we’ve realized that real-time is no longer this flashy nice-to-have in our applications. It is our users expectation. Whether those users are our bosses looking at real-time monitoring dashboard or the general public wanting updates on their food deliveries precise location. We at MongoDB sought out to make it easier for you to rise to the high expectations your users have. And with that, in MongoDB 3.6 we are introducing Change Streams. In this talk, I will give you a simple definition of what change streams are and the power they possess. Then we will go into some one the charactertics change streams have. Finally, we will discuss how you can avoid some potential pitfalls.
  • #6: So let’s start with a simple definition. Change streams allow you to watch all the changes against a given collection. So, when you open change streams against a collection you will see all of the changes applied to documents that belong to that collection. On each change a listening application will be notified with a document describing the change. Imagine this scenario, I have a smart thermometer within my apartment. Every second it inserts a document into MongoDB with temperature data. Change streams can then notify any listening application to every change in my temperature collection. So as the thermometer inserts new data, change streams will inform my listening action handler. In this case, the action handler is an application I built to turn on a fan every time the temperature goes above 70 degrees. Don’t let the simplicity of this example fool you, this concept can be applied to back-office management applications to end user applications. Change streams are extremely powerful
  • #7: So, this slide is to show you how incredibly simple it is to implement change streams in your application. This example happens to be in node. Here, I am defining a change stream. Then starting it where every change gets printed out. It’s extremely simple and incredibly powerful. With change stream, you get a real-time feed of the changes to your data, enabling your application to react to these changes immediately.
  • #9: Now we are going to move into some of the characteristics of change streams.
  • #17: Now we are going to move into some of the characteristics of change streams.
  • #18: Now we are going to move into some of the characteristics of change streams.
  • #19: Now we are going to move into some of the characteristics of change streams.
  • #20: Now we are going to move into some of the characteristics of change streams.
  • #21: Now we are going to move into some of the characteristics of change streams.
  • #45: The oplog is an internal mechanism that tracks all changes across the entire cluster, whether they are data or system changes. The