SlideShare une entreprise Scribd logo
1  sur  175
Télécharger pour lire hors ligne
While you wait…
...let’s get some things out of the way
• Install MongoDB 3.6 or 4.0
• https://docs.mongodb.com/manual/installation/#mongodb-community-edition
• Install Node 8 or Node 10
• https://nodejs.org/en/
• Download the code we’ll start with, and unzip it
• https://github.com/hswolff/dibs/archive/tutorial-start.zip
• Install all dependencies
• cd client && npm install && cd ../server && npm install
Got Dibs? Building a
Real-Time Bidding App
with Change Streams
A tutorial by Harry Wolff
Harry Wolff
Lead Engineer, MongoDB
@hswolff
MongoDB
Cloud Manager
& Atlas
The Console Log
What are we
doing today?
Building a Real-Time Bidding App
with Change Streams
BUT FIRST
Story
Time
Build an app
Easy and fun to use
Has to be real time
And we need it now!
Real time?
Change Streams!
Demo
Application Architecture
API
Server
(Node)
MongoDB
Client
(React)
Outline
1. Prerequisites
2. Create the Server
3. Create the Client
4. Let's call dibs
5. To real time, and beyond!
Outline
1. Prerequisites
2. Create the Server
a. Set up MongoDB
b. Create server folder
c. Connect to MongoDB
d. Set up our API
e. Create API endpoints
3. Create the Client
a. Create client folder
b. Connect to our API
c. Render all dibs
d. Add support for creating a dib
e. Enable a user to log in
4. Let's call dibs
a. Server support
b. Client support
5. To real time, and beyond!
a. Server support
b. Client support
Outline
1. Prerequisites
2. Create the Server
a. Set up MongoDB
b. Create server folder
c. Connect to MongoDB
d. Set up our API
e. Create API endpoints
3. Create the Client
a. Create client folder
b. Connect to our API
c. Render all dibs
d. Add support for creating a dib
e. Enable a user to log in
4. Let's call dibs
a. Server support
b. Client support
5. To real time, and beyond!
a. Server support
b. Client support
Change
Streams
Source Code
We’re starting with a partially complete
codebase.
You’ll see TODO comments throughout.
By the end of today all of those will be
completed.
Source Code
All source code for each step is
available online for quick reference.
https://github.com/hswolff/dibs/tree/tutorial
Download a copy of the code for easy reference
https://github.com/hswolff/dibs/archive/tutorial.zip
Download a copy of these slides
http://bit.ly/mdbw18-dibs
Slides
Create the Server
Set up MongoDB
# Create the folder where the database will save its data.
mkdir db
# Start the mongo daemon, and leave it open in a terminal.
mongod --port 27017 --dbpath $(pwd)/db --replSet rs0
# Instantiate the replica set. Only need to run this one time.
mongo --eval "rs.initiate()"
Set up MongoDB
Set up MongoDB
# Connect to the db from a different shell.
mongo
# You should see
rs0:PRIMARY>
Set up MongoDB
Connect to MongoDB
open server/db.js
Connect to MongoDB
function LetsCode(){}
Connect to MongoDB
const mongoose = require('mongoose');
const dibScheme = new mongoose.Schema(
{
title: {
type: String,
required: true,
},
creator: {
type: String,
required: true,
},
},
{ timestamps: true }
);
const Dib = mongoose.model('Dib', dibScheme);
Connect to MongoDB
const Models = {
Dib,
};
exports.Models = Models;
const dbUri = 'mongodb://localhost:27017/dibs';
async function connect() {
await mongoose.connect(dbUri);
console.log('Connected to MongoDB');
}
exports.connect = connect;
1. Open node REPL
a. node
2. Import db file and connect to MongoDB
a. const db = require('./db);
b. db.connect();
3. Find all documents
a. db.Models.Dib.find().then(console.log);
4. Create a document
a. db.Models.Dib.create({ title: 'First Item', creator: 'Yay'
}).then(console.log);
5. Find all documents again
Connect to MongoDB: Let’s test it
1. Try and create a document that doesn’t
pass validation.
2. Use the Mongoose method to find one
document
(hint http://mongoosejs.com/docs/queries.html)
Connect to MongoDB: Let’s test it
https://github.com/hswolff/dibs/blob/tutori
al/step2a-d/server/db.js
Connect to MongoDB: Catch Up
Set up our API server
Set up our API
open server/server.js
function LetsCode(){}
Set up our API
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const PORT = process.env.PORT || 8080;
const DOMAIN = process.env.DOMAIN || 'http://localhost' ;
Set up our API: server.js
function createServer() {
const app = express();
app.use(cors(), bodyParser.json());
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(PORT, () => {
console.log(`Server ready at ${DOMAIN}:${PORT}/`);
});
}
createServer();
Set up our API: server.js
1. Start server
a. node server.js
2. Open browser: http://localhost:8080/
3. What do you see?
Set up our API: Test It
1. Change a handler to return JSON to the
browser
2. Add a new handler that says ‘Goodbye’
3. Add a handler that takes in a parameter
so we can say `Hello ${name}`
(hint: https://expressjs.com/en/guide/routing.html)
Set up our API: Exercise
https://github.com/hswolff/dibs/blob/tutori
al/step2a-d/server/server.js
Set up our API: Catch up
Create API endpoints
Create API endpoints
# We want to expose our MongoDB data
through an API
# We’re going to expose all API methods
under an /api route namespace.
open server/api.js
function LetsCode(){}
Create API endpoints
const express = require('express');
module.exports = function createApi({ Models }) {
const api = express.Router();
// Get all Dibs
api.get('/dibs', async (req, res) => {
res.json({
data: await Models.Dib.find().sort('-createdAt'),
});
});
Create API endpoints: api.js
// Create a Dib
api.post('/dibs', async (req, res) => {
const { creator, title } = req.body;
if (!creator || !title) {
return res.status(500).json({
error: 'Must include a "creator" and a
"title".',
});
}
res.json({
data: await Models.Dib.create({
creator ,
title,
}),
});
});
return api;
};
Create API endpoints: api.js
const db = require('./db');
const createApi = require('./api');
// inside createServer
try {
await db.connect();
} catch (error) {
console.error(error.message);
console.error('Closing server');
process.exit(1);
}
app.use('/api', createApi({ Models: db.Models }));
Create API endpoints: server.js
Check GET and browse to:
http://localhost:8080/api/dibs
Check POST with cURL
curl --data '{"title": "Hello from Curl", "creator": "Mr. Curly"}' 
-X POST --header "Content-Type: application/json" 
http://localhost:8080/api/dibs
Create API endpoints: Test It
Create API endpoints: Catch Up
https://github.com/hswolff/dibs/tree/tutori
al/step2e/server
Guess what?
Outline
1. Prerequisites
2. Create the Server
a. Set up MongoDB
b. Create server folder
c. Connect to MongoDB
d. Set up our API
e. Create API endpoints
3. Create the Client
a. Create client folder
b. Connect to our API
c. Render all dibs
d. Add support for creating a dib
e. Enable a user to log in
4. Let's call dibs
a. Server support
b. Client support
5. To real time, and beyond!
a. Server support
b. Client support
Create the Client
Create client folder
Create client folder
We used Create React App to scaffold our
client
Create client folder: Test It
cd client
npm start
Does your browser open?
Connect to our API
Connect to our API
open src/services/api.js
function LetsCode(){}
Connect to our API
Connect to our API: src/services/api.js
const baseUrl = 'http://localhost:8080' ;
function fetchWrapper(apiPath, options) {
return fetch(`${baseUrl}/api${apiPath}`, options).then(res => res.json());
}
export default {
getDibs() {
return fetchWrapper('/dibs');
},
createDib({ creator, title }) {
return fetchWrapper('/dibs', {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
creator,
title,
}),
});
},
};
Connect to our API: src/services/api.js
1. Ensure your API server is running.
2. Ensure your client environment is running.
3. Go to client/src/index.js.
4. We’re going to expose our client API globally.
Connect to our API: Test It
import api from './services/api';
window.api = api;
Connect to our API: client/src/index.js
5. Go to your browser and open the Developer Tools
(for Chrome go to View > Developer > Developer Tools)
6. Go to the “Console” tab
7. Type ‘api’ in the console. You should see your API code!
8. Exercise: Try making a request for “getDibs”
Answer: api.getDibs().then(console.log)
9. Exercise: Try creating a new dib
Answer: api.createDib({ creator: 'Browser', title: 'From
the client!' }).then(console.log)
Connect to our API: Test It
Remove our debug code from index.js
Connect to our API: Cleanup
https://github.com/hswolff/dibs/blob/tutorial/ste
p3a-c/client/src/services/api.js
Connect to our API: Catch up
Render all dibs
# We want to fetch our data from our server API
# We’re going to load the data in our HomePage
# We’re going to use React’s lifecycle methods to do so
# Namely the componentDidMount lifecycle method
open src/components/HomePage.js
Render all dibs: Load the data
function LetsCode(){}
Render all dibs
import React, { Component } from 'react';
export default class HomePage extends Component {
render() {
return (
<div>
<header>
<h1>Got Dibs?</h1>
</header>
</div>
);
}
}
Render all dibs: components/HomePage.js
import React, { Component } from 'react';
import './App.css';
import HomePage from './components/HomePage';
class App extends Component {
render() {
return (
<div className="App-content">
<HomePage />
</div>
);
}
}
export default App;
Render all dibs: src/App.js
.App-content {
width: 600px;
margin: 20px auto;
}
Render all dibs: src/App.css
import React, { Component } from 'react';
import api from '../services/api';
export default class HomePage extends Component {
state = {
dibs: [],
};
componentDidMount = async () => {
const result = await api.getDibs();
this.setState({ dibs: result.data });
};
render() {
const { dibs } = this.state;
return (
<div>
<header>
<h1>Got Dibs?</h1>
</header>
<div>
{dibs.map(dib => (
<pre key={dib._id}>
{JSON.stringify(dib, null, 2)}
</pre>
))}
</div>
</div>
);
}
Render all dibs: components/HomePage.js
Render all dibs: Test It
# Now we want to render each item a little better
# To do so we’ll use the component “DibCell”
open components/DibCell.js
Render all dibs: With style!
function LetsCode(){}
Render all dibs: With style!
import React, { Component } from 'react';
import './DibCell.css';
export default class DibCell extends Component {
render() {
const { title, creator } = this.props;
return (
<div className="dib-container">
<div className="dib-left">
<div className="dib-creator">
<b>{creator}</b> is offering
</div>
<div className="dib-title">{title}</div>
</div>
<div className="dib-right" />
</div>
);
}
}
Render all dibs: components/DibCell.js
.dib-container {
margin: 20px 0;
padding: 20px 0;
display: flex;
}
.dib-left {
width: 70%;
padding-right: 20px;
margin-right: 20px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.dib-creator {
font-size: 0.9rem;
}
.dib-title {
font-size: 2rem;
}
.dib-right {
width: 30%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
Render all dibs: components/DibCell.css
Render all dibs: components/HomePage.js
import DibCell from './DibCell';
render() {
const { dibs } = this.state;
return (
<div>
<header>
<h1>Got Dibs?</h1>
</header>
<div>{dibs.map(dib => <DibCell key={dib._id} {...dib} />)}</div>
</div>
);
}
Render all dibs: Test It
https://github.com/hswolff/dibs/tree/tuto
rial/step3a-c/client/src/components
Render all dibs: Catch up
Ok.
So.
That was a lot.
BUT
SO
LET’S KEEP
GOING
Add support for creating
a dib
# Using our CreateNewDib component
# We need to hook it up to actually create the new dib.
open src/components/CreateNewDib.js
Add support for creating a dib
function LetsCode(){}
Add support for creating a dib
import React, { Component } from 'react';
export default class CreateNewDib extends Component {
state = {
title: '',
error: null,
};
render() {
const { error, title } = this.state;
return (
<div>
{error}
<textarea
autoFocus
tabIndex={1}
placeholder="Create New Dib"
value={title}
onChange={e => this.setState({ title:
e.target.value })}
/>
<br />
<button>Create New Dib</button>
</div>
);
}
}
Add support for creating a dib: CreateNewDib
import CreateNewDib from './CreateNewDib';
render() {
const { dibs } = this.state;
return (
<div>
<header>
<h1>Got Dibs?</h1>
</header>
<CreateNewDib />
<div>{dibs.map(dib => <DibCell key={dib._id} {...dib} />)}</div>
</div>
);
}
Add support for creating a dib: HomePage
import api from '../services/api';
<button onClick={this.createNew}>Create New Dib</button>
createNew = async e => {
e.preventDefault();
this.setState({ error: null });
try {
await api.createDib({
title: this.state.title,
creator: 'Fake Creator',
});
this.setState({ title: '' });
this.props.onSuccess();
} catch (error) {
this.setState({ error: error.message });
}
};
Add support for creating a dib: CreateNewDib
componentDidMount = () => {
this.loadDibs();
};
loadDibs = async () => {
const result = await api.getDibs();
this.setState({ dibs: result.data });
};
<CreateNewDib onSuccess={this.loadDibs} />
Add support for creating a dib: HomePage
1. Try creating a new dib!
2. Does your page refresh with the new dib?
Add support for creating a dib: Test It
1. Style CreateNewDib UI
2. Add a button on the HomePage which shows and hides the
CreateNewDib component
Add support for creating a dib: Exercise
https://github.com/hswolff/dibs/tree/tuto
rial/step3d/client/src/components
Add support for creating a dib: Catch Up
Enable a user to log in
Enable a user to log in
# We need to enable a user to give us a username so we can
show the right person that created a dib
# We store the user in localStorage to persist it between
refreshes
# We’re going to use the SignIn component to let a user sign
in.
open src/components/SignIn.js
function LetsCode(){}
Enable a user to log in
import React, { Component } from 'react';
export default class SignIn extends Component {
state = {
input: '',
};
logIn = () => {
this.props.onUsernameChange(this.state.input);
};
logOut = () => {
this.props.onUsernameChange(null);
};
render() {
const { username } = this.props;
const { input } = this.state;
if (username) {
return (
<div>
Logged in as: < b>{username}</b>
<button onClick={this.logOut}>Log Out</ button>
</div>
);
}
return (
<div>
<input
value={input}
onChange={e => this.setState({ input: e.target.value })}
/>
<button onClick={this.logIn}>Log In</button>
</div>
);
}
}
Enable a user to log in: SignIn.js
import SignIn from './SignIn';
state = {
dibs: [],
username: localStorage.getItem('username'),
};
onUsernameChange = username => {
localStorage.setItem('username', username);
this.setState({ username });
};
render() {
const { dibs, username } = this.state;
return (
<div>
<header>
<h1>Got Dibs?</h1>
</header>
<SignIn username={username}
onUsernameChange={this.onUsernameChange} />
<br />
<CreateNewDib onSuccess={this.loadDibs}
username={username} />
<div>{dibs.map(dib => <DibCell key={dib._id} {...dib}
/>)}</div>
</div>
);
Enable a user to log in: HomePage.js
createNew = async e => {
e.preventDefault();
this.setState({ error: null });
try {
await api.createDib({
title: this.state.title,
creator: this.props.username,
});
this.setState({ title: '' });
this.props.onSuccess();
} catch (error) {
this.setState({ error: error.message });
}
};
Enable a user to log in: CreateNewDib.js
1. Try creating a new dib!
2. Do you see it appear?
Enable a user to log in: Test it
1. Only show CreateNewDib if a username is set
2. Show an error if a user puts in an empty username
3. Style SignIn component
Enable a user to log in: Exercise
https://github.com/hswolff/dibs/tree/tuto
rial/step3e/client/src/components
Enable a user to log in: Catch Up
Hey.
Guess what?
We did it!
Outline
1. Prerequisites
2. Create the Server
a. Set up MongoDB
b. Create server folder
c. Connect to MongoDB
d. Set up our API
e. Create API endpoints
3. Create the Client
a. Create client folder
b. Connect to our API
c. Render all dibs
d. Add support for creating a dib
e. Enable a user to log in
4. Let's call dibs
a. Server support
b. Client support
5. To real time, and beyond!
a. Server support
b. Client support
Let's call dibs
Server support
# We need to extend our Schema to support claiming a Dib
Server support
function LetsCode(){}
Server support: Schema
Server support: server/db.js
const dibScheme = new mongoose.Schema(
{
title: {
type: String,
required: true,
},
creator: {
type: String,
required: true,
},
claimed: { // New
user: String,
time: Date,
},
},
{ timestamps: true }
);
const Dib = mongoose.model('Dib', dibScheme);
Server support
# We need to add a new endpoint
# Endpoint adds support for a user to claim a dib
# We need to validate the data sent
Need to make sure all data required is sent
Need to make sure that the dib exists
Need to make sure a dib has not already been claimed
function LetsCode(){}
Server support: Endpoint
// Claim a Dib
api.put('/dibs/:dibId', async (req, res) => {
const { dibId } = req.params;
const { user } = req.body;
if (!user) {
return res.status(500).json({
error: 'No "user" given to claim Dib.',
});
}
let dib;
try {
dib = await Models.Dib.findById(dibId);
} catch (error) {
return res.status(500).json({
error: 'Cannot find Dib with given id',
});
}
Server support: server/api.js
if (dib.claimed.user) {
return res.status(500).json({
error: 'Dib has already been claimed!',
});
}
dib.claimed.user = user;
dib.claimed.time = new Date();
res.json({
data: await dib.save(),
});
});
Server support: Catch Up
https://github.com/hswolff/dibs/tree/tuto
rial/step4/server
Client support
# Add a new method to our API service to call our new API
endpoint called “claimDib”
Client support
function LetsCode(){}
Client support
Client support: client/src/services/api.js
claimDib({ id, user }) {
return fetchWrapper(`/dibs/${id}`, {
method: 'PUT',
headers: {
'content-type' : 'application/json' ,
},
body: JSON.stringify({
user,
}),
});
},
# Add a handler to actually make our API call to claim a dib
# Update our “Dibs?” text to say “Claimed!” if the dib is
already taken
open src/components/DibCell.js
Client support
function LetsCode(){}
Client support
.dib-claim-button {
height: 100%;
width: 100%;
font-size: 50px;
cursor: pointer;
}
Client support: client/src/DibCell.js
const { title, creator, claimed } = this.props;
const isClaimed = claimed && claimed.user != null;
return (
<div className="dib-container">
<div className="dib-left">
<div className="dib-creator">
<b>{creator}</b> is offering
</div>
<div className="dib-title">{title}</div>
</div>
<div className="dib-right">
<button className="dib-claim-button">
{isClaimed ? 'Claimed!' : 'Dibs?'}
</button>
</div>
</div>
);
Client support: client/src/DibCell.js
<button className="dib-claim-button" onClick={this.claimDib}>
{isClaimed ? 'Claimed!' : 'Dibs?'}
</button>
claimDib = async () => {
this.setState({ error: null });
try {
await api.claimDib({
id: this.props._id,
user: this.props.username,
});
} catch (error) {
console.error('Error claiming dib', error);
}
};
Client support: client/src/HomePage.js
<div>
{dibs.map(dib => (
<DibCell key={dib._id} {...dib} username={username} />
))}
</div>
1. Try claiming a dib!
2. Refresh the page
3. Does it show that it’s claimed?
Client support: Try It
1. Show an error if a dib has already been claimed
2. Disable the button if a user is not logged in
Client support: Exercise
https://github.com/hswolff/dibs/tree/tuto
rial/step4/client/src
Client support: Catch Up
Guess what we got?
Outline
1. Prerequisites
2. Create the Server
a. Set up MongoDB
b. Create server folder
c. Connect to MongoDB
d. Set up our API
e. Create API endpoints
3. Create the Client
a. Create client folder
b. Connect to our API
c. Render all dibs
d. Add support for creating a dib
e. Enable a user to log in
4. Let's call dibs
a. Server support
b. Client support
5. To real time, and beyond!
a. Server support
b. Client support
To real time, and beyond!
Server support
# We want to open a Change Stream to be notified of when our
collection in MongoDB changes
# Change Streams are a new feature in MongoDB 3.6
# Change Streams allow applications to access real-time data
changes without the complexity and risk of tailing the oplog.
(docs)
Server support
function LetsCode(){}
Server support
Server support: db.js
async function connect() {
await mongoose.connect(dbUri);
console.log('Connected to MongoDB');
const dibChangeStream = Models.Dib.collection.watch({
fullDocument: 'updateLookup',
});
dibChangeStream.on('change', result => {
console.log(JSON.stringify(result, null, 2));
});
}
# Try making a new dib!
# Try claiming a dib!
# Should see output from your server.
Server support: Test Change Stream
So let’s talk real time.
We want our updates to show immediately.
There’s one technology good for that…
WebSockets!
WebSockets are an advanced technology that makes it possible to
open an interactive communication session between the user's
browser and a server. With this API, you can send messages to a
server and receive event-driven responses without having to poll
the server for a reply.
- https://developer.mozilla.org/en-US/docs/Web/API/WebSockets
_API
# We’re using socket.io as our WebSocket server
# Create our WebSocket server
Server support
function LetsCode(){}
Server support
Server support: server.js
const http = require('http');
const socketIo = require('socket.io');
// ...
const httpServer = http.Server(app);
const io = socketIo(httpServer);
// ...
await db.connect(io);
// ...
httpServer.listen(PORT, () => {
console.log(`Server ready at ${DOMAIN}:${PORT}/`);
});
# Now we want to share those changes to the client
# And we’ll do that through our WebSocket
Server support
function LetsCode(){}
Server support
Server support: db.js
async function connect(io) {
await mongoose.connect(dbUri);
console.log('Connected to MongoDB');
const dibChangeStream = Models.Dib.collection.watch({
fullDocument: 'updateLookup',
});
dibChangeStream.on('change', result => {
io.emit('dib changeEvent', {
type: result.operationType,
dib: {
claimed: {},
...result.fullDocument,
id: result.fullDocument._id,
},
});
});
}
https://github.com/hswolff/dibs/tree/tuto
rial/step5/server
Server support: Catch Up
Client support
# We need to be able to connect to our WebSocket server
# To do that we’ll use…
# socket.io on the client!
Client support
# Let’s add a method for us to connect to our WebSocket server
# In particular we want to subscribe to our ‘dib changeEvent’
# When that event happens we want our callback to be called
open src/services/api.js
Client support
function LetsCode(){}
Client support
Client support: client/src/services/api.js
import io from 'socket.io-client';
function createSocket() {
const socket = io(baseUrl);
return socket;
}
subscribeToDibChanges(cb) {
createSocket().on('dib changeEvent', cb);
},
# Now let’s actually subscribe to the WebSocket
# We’ll update our UI when a new event comes in
Client support
function LetsCode(){}
Client support
componentDidMount = () => {
this.loadDibs();
api.subscribeToDibChanges (event => {
const { dib, type } = event;
const currentDibs = this.state.dibs;
if (type === 'update') {
return this.setState({
dibs: [
... currentDibs .map(prevDib => {
if (prevDib._id === dib._id) {
return dib;
}
return prevDib;
}),
],
});
}
// If adding a new dib
return this.setState({
dibs: [dib, ...currentDibs],
});
});
};
Client support: components/HomePage.js
1. Open another browser in Incognito
2. Try making a new dib.
3. Do you see it show up in the other browser??
Client support: Test it!
https://github.com/hswolff/dibs/tree/tuto
rial/step5/client/src
Client support: Catch Up
So.
Uh,
Guess what?
You Have Dibs!
Outline
1. Prerequisites
2. Create the Server
a. Set up MongoDB
b. Create server folder
c. Connect to MongoDB
d. Set up our API
e. Create API endpoints
3. Create the Client
a. Create client folder
b. Connect to our API
c. Render all dibs
d. Add support for creating a dib
e. Enable a user to log in
4. Let's call dibs
a. Server support
b. Client support
5. To real time, and beyond!
a. Server support
b. Client support
Let’s Recap
1. Instantiated our own local MongoDB
2. Created an entire API server, powered by Express
3. Opened a MongoDB Change Stream
4. Created a WebSocket server that tells the client when data
in our MongoDB Change Stream changed
5. Created a React application
6. Connected to our API server on the client
7. Added the ability to list all our dibs
8. Added the ability to create a dib
9. Added the ability to claim a dib
10. ...and we made it all work in real time!
Let’s Recap
Take it further
1. Location of Dib.
2. Price/bounty of Dib.
3. Auth with Google
4. Real-time comments on a Dib
5. Able to edit Dibs that you created.
6. Able to un-claim a Dib if you're the creator of the dib.
7. ...and more!
Take it further
Got Dibs? Building a
Real-Time Bidding App
with Change Streams
A tutorial by Harry Wolff
Harry Wolff
Lead Engineer, MongoDB
@hswolff
TheConsoleLog.com

Contenu connexe

Tendances

Dockerize node.js application
Dockerize node.js applicationDockerize node.js application
Dockerize node.js applicationSeokjun Kim
 
Extending Kubernetes – Admission webhooks
Extending Kubernetes – Admission webhooksExtending Kubernetes – Admission webhooks
Extending Kubernetes – Admission webhooksStefan Schimanski
 
Building a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQueryBuilding a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQueryTatsuhiko Miyagawa
 
Deploying Symfony | symfony.cat
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.catPablo Godel
 
Gearman work queue in php
Gearman work queue in phpGearman work queue in php
Gearman work queue in phpBo-Yi Wu
 
Transforming Infrastructure into Code - Importing existing cloud resources u...
Transforming Infrastructure into Code  - Importing existing cloud resources u...Transforming Infrastructure into Code  - Importing existing cloud resources u...
Transforming Infrastructure into Code - Importing existing cloud resources u...Shih Oon Liong
 
Antons Kranga Building Agile Infrastructures
Antons Kranga   Building Agile InfrastructuresAntons Kranga   Building Agile Infrastructures
Antons Kranga Building Agile InfrastructuresAntons Kranga
 
HTML5 Real-Time and Connectivity
HTML5 Real-Time and ConnectivityHTML5 Real-Time and Connectivity
HTML5 Real-Time and ConnectivityPeter Lubbers
 
One commit, one release. Continuously delivering a Symfony project.
One commit, one release. Continuously delivering a Symfony project.One commit, one release. Continuously delivering a Symfony project.
One commit, one release. Continuously delivering a Symfony project.Javier López
 
Continous Delivering a PHP application
Continous Delivering a PHP applicationContinous Delivering a PHP application
Continous Delivering a PHP applicationJavier López
 
How to test code with mruby
How to test code with mrubyHow to test code with mruby
How to test code with mrubyHiroshi SHIBATA
 
Seven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech TalkSeven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech TalkRed Hat Developers
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Racksickill
 
Continuous Integration: SaaS vs Jenkins in Cloud
Continuous Integration: SaaS vs Jenkins in CloudContinuous Integration: SaaS vs Jenkins in Cloud
Continuous Integration: SaaS vs Jenkins in CloudIdeato
 
PHP & JavaScript & CSS Coding style
PHP & JavaScript & CSS Coding stylePHP & JavaScript & CSS Coding style
PHP & JavaScript & CSS Coding styleBo-Yi Wu
 

Tendances (20)

Dockerize node.js application
Dockerize node.js applicationDockerize node.js application
Dockerize node.js application
 
Extending Kubernetes – Admission webhooks
Extending Kubernetes – Admission webhooksExtending Kubernetes – Admission webhooks
Extending Kubernetes – Admission webhooks
 
Building a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQueryBuilding a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQuery
 
Plack at YAPC::NA 2010
Plack at YAPC::NA 2010Plack at YAPC::NA 2010
Plack at YAPC::NA 2010
 
Deploying Symfony | symfony.cat
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.cat
 
Gearman work queue in php
Gearman work queue in phpGearman work queue in php
Gearman work queue in php
 
Transforming Infrastructure into Code - Importing existing cloud resources u...
Transforming Infrastructure into Code  - Importing existing cloud resources u...Transforming Infrastructure into Code  - Importing existing cloud resources u...
Transforming Infrastructure into Code - Importing existing cloud resources u...
 
Firebase slide
Firebase slideFirebase slide
Firebase slide
 
Antons Kranga Building Agile Infrastructures
Antons Kranga   Building Agile InfrastructuresAntons Kranga   Building Agile Infrastructures
Antons Kranga Building Agile Infrastructures
 
HTML5 Real-Time and Connectivity
HTML5 Real-Time and ConnectivityHTML5 Real-Time and Connectivity
HTML5 Real-Time and Connectivity
 
One commit, one release. Continuously delivering a Symfony project.
One commit, one release. Continuously delivering a Symfony project.One commit, one release. Continuously delivering a Symfony project.
One commit, one release. Continuously delivering a Symfony project.
 
Continous Delivering a PHP application
Continous Delivering a PHP applicationContinous Delivering a PHP application
Continous Delivering a PHP application
 
はじめてのSymfony2
はじめてのSymfony2はじめてのSymfony2
はじめてのSymfony2
 
How to test code with mruby
How to test code with mrubyHow to test code with mruby
How to test code with mruby
 
Seven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech TalkSeven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech Talk
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
 
Continuous Integration: SaaS vs Jenkins in Cloud
Continuous Integration: SaaS vs Jenkins in CloudContinuous Integration: SaaS vs Jenkins in Cloud
Continuous Integration: SaaS vs Jenkins in Cloud
 
Intro to PSGI and Plack
Intro to PSGI and PlackIntro to PSGI and Plack
Intro to PSGI and Plack
 
Plack at OSCON 2010
Plack at OSCON 2010Plack at OSCON 2010
Plack at OSCON 2010
 
PHP & JavaScript & CSS Coding style
PHP & JavaScript & CSS Coding stylePHP & JavaScript & CSS Coding style
PHP & JavaScript & CSS Coding style
 

Similaire à MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App with Change Streams

Parse cloud code
Parse cloud codeParse cloud code
Parse cloud code維佋 唐
 
Into The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api'sInto The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api'sOrtus Solutions, Corp
 
From development environments to production deployments with Docker, Compose,...
From development environments to production deployments with Docker, Compose,...From development environments to production deployments with Docker, Compose,...
From development environments to production deployments with Docker, Compose,...Jérôme Petazzoni
 
Webinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsWebinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsMongoDB
 
Making a small QA system with Docker
Making a small QA system with DockerMaking a small QA system with Docker
Making a small QA system with DockerNaoki AINOYA
 
Cocoapods and Most common used library in Swift
Cocoapods and Most common used library in SwiftCocoapods and Most common used library in Swift
Cocoapods and Most common used library in SwiftWan Muzaffar Wan Hashim
 
20170321 docker with Visual Studio 2017
20170321 docker with Visual Studio 201720170321 docker with Visual Studio 2017
20170321 docker with Visual Studio 2017Takayoshi Tanaka
 
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. JavaCloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. JavaJan Stamer
 
Ruby on Rails Kickstart 101 & 102
Ruby on Rails Kickstart 101 & 102Ruby on Rails Kickstart 101 & 102
Ruby on Rails Kickstart 101 & 102Heng-Yi Wu
 
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
 Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbsAWS Chicago
 
State ofappdevelopment
State ofappdevelopmentState ofappdevelopment
State ofappdevelopmentgillygize
 
Itb 2021 - Bulding Quick APIs by Gavin Pickin
Itb 2021 - Bulding Quick APIs by Gavin PickinItb 2021 - Bulding Quick APIs by Gavin Pickin
Itb 2021 - Bulding Quick APIs by Gavin PickinGavin Pickin
 
What is Node.js? (ICON UK)
What is Node.js? (ICON UK)What is Node.js? (ICON UK)
What is Node.js? (ICON UK)Tim Davis
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.jsVikash Singh
 
Rails web api 开发
Rails web api 开发Rails web api 开发
Rails web api 开发shaokun
 
Continuous Integration and Code Coverage in Xcode
Continuous Integration and Code Coverage in XcodeContinuous Integration and Code Coverage in Xcode
Continuous Integration and Code Coverage in XcodeHiep Luong
 
Docker module 1
Docker module 1Docker module 1
Docker module 1Liang Bo
 
node.js: Javascript's in your backend
node.js: Javascript's in your backendnode.js: Javascript's in your backend
node.js: Javascript's in your backendDavid Padbury
 

Similaire à MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App with Change Streams (20)

Parse cloud code
Parse cloud codeParse cloud code
Parse cloud code
 
Into The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api'sInto The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api's
 
From development environments to production deployments with Docker, Compose,...
From development environments to production deployments with Docker, Compose,...From development environments to production deployments with Docker, Compose,...
From development environments to production deployments with Docker, Compose,...
 
Webinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsWebinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.js
 
Making a small QA system with Docker
Making a small QA system with DockerMaking a small QA system with Docker
Making a small QA system with Docker
 
Cocoapods and Most common used library in Swift
Cocoapods and Most common used library in SwiftCocoapods and Most common used library in Swift
Cocoapods and Most common used library in Swift
 
MongoDB and Node.js
MongoDB and Node.jsMongoDB and Node.js
MongoDB and Node.js
 
20170321 docker with Visual Studio 2017
20170321 docker with Visual Studio 201720170321 docker with Visual Studio 2017
20170321 docker with Visual Studio 2017
 
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. JavaCloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
 
Excelian hyperledger walkthrough-feb17
Excelian hyperledger walkthrough-feb17Excelian hyperledger walkthrough-feb17
Excelian hyperledger walkthrough-feb17
 
Ruby on Rails Kickstart 101 & 102
Ruby on Rails Kickstart 101 & 102Ruby on Rails Kickstart 101 & 102
Ruby on Rails Kickstart 101 & 102
 
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
 Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
 
State ofappdevelopment
State ofappdevelopmentState ofappdevelopment
State ofappdevelopment
 
Itb 2021 - Bulding Quick APIs by Gavin Pickin
Itb 2021 - Bulding Quick APIs by Gavin PickinItb 2021 - Bulding Quick APIs by Gavin Pickin
Itb 2021 - Bulding Quick APIs by Gavin Pickin
 
What is Node.js? (ICON UK)
What is Node.js? (ICON UK)What is Node.js? (ICON UK)
What is Node.js? (ICON UK)
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.js
 
Rails web api 开发
Rails web api 开发Rails web api 开发
Rails web api 开发
 
Continuous Integration and Code Coverage in Xcode
Continuous Integration and Code Coverage in XcodeContinuous Integration and Code Coverage in Xcode
Continuous Integration and Code Coverage in Xcode
 
Docker module 1
Docker module 1Docker module 1
Docker module 1
 
node.js: Javascript's in your backend
node.js: Javascript's in your backendnode.js: Javascript's in your backend
node.js: Javascript's in your backend
 

Plus de MongoDB

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

Plus de MongoDB (20)

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

Dernier

A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 

Dernier (20)

A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 

MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App with Change Streams

  • 1. While you wait… ...let’s get some things out of the way • Install MongoDB 3.6 or 4.0 • https://docs.mongodb.com/manual/installation/#mongodb-community-edition • Install Node 8 or Node 10 • https://nodejs.org/en/ • Download the code we’ll start with, and unzip it • https://github.com/hswolff/dibs/archive/tutorial-start.zip • Install all dependencies • cd client && npm install && cd ../server && npm install
  • 2. Got Dibs? Building a Real-Time Bidding App with Change Streams A tutorial by Harry Wolff
  • 3. Harry Wolff Lead Engineer, MongoDB @hswolff
  • 7. Building a Real-Time Bidding App with Change Streams BUT FIRST
  • 9.
  • 10.
  • 11.
  • 12. Build an app Easy and fun to use Has to be real time And we need it now!
  • 15. Demo
  • 17. Outline 1. Prerequisites 2. Create the Server 3. Create the Client 4. Let's call dibs 5. To real time, and beyond!
  • 18. Outline 1. Prerequisites 2. Create the Server a. Set up MongoDB b. Create server folder c. Connect to MongoDB d. Set up our API e. Create API endpoints 3. Create the Client a. Create client folder b. Connect to our API c. Render all dibs d. Add support for creating a dib e. Enable a user to log in 4. Let's call dibs a. Server support b. Client support 5. To real time, and beyond! a. Server support b. Client support
  • 19. Outline 1. Prerequisites 2. Create the Server a. Set up MongoDB b. Create server folder c. Connect to MongoDB d. Set up our API e. Create API endpoints 3. Create the Client a. Create client folder b. Connect to our API c. Render all dibs d. Add support for creating a dib e. Enable a user to log in 4. Let's call dibs a. Server support b. Client support 5. To real time, and beyond! a. Server support b. Client support Change Streams
  • 20. Source Code We’re starting with a partially complete codebase. You’ll see TODO comments throughout. By the end of today all of those will be completed.
  • 21. Source Code All source code for each step is available online for quick reference. https://github.com/hswolff/dibs/tree/tutorial Download a copy of the code for easy reference https://github.com/hswolff/dibs/archive/tutorial.zip
  • 22. Download a copy of these slides http://bit.ly/mdbw18-dibs Slides
  • 23.
  • 24.
  • 27. # Create the folder where the database will save its data. mkdir db # Start the mongo daemon, and leave it open in a terminal. mongod --port 27017 --dbpath $(pwd)/db --replSet rs0 # Instantiate the replica set. Only need to run this one time. mongo --eval "rs.initiate()" Set up MongoDB
  • 28. Set up MongoDB # Connect to the db from a different shell. mongo # You should see rs0:PRIMARY>
  • 33. const mongoose = require('mongoose'); const dibScheme = new mongoose.Schema( { title: { type: String, required: true, }, creator: { type: String, required: true, }, }, { timestamps: true } ); const Dib = mongoose.model('Dib', dibScheme); Connect to MongoDB const Models = { Dib, }; exports.Models = Models; const dbUri = 'mongodb://localhost:27017/dibs'; async function connect() { await mongoose.connect(dbUri); console.log('Connected to MongoDB'); } exports.connect = connect;
  • 34. 1. Open node REPL a. node 2. Import db file and connect to MongoDB a. const db = require('./db); b. db.connect(); 3. Find all documents a. db.Models.Dib.find().then(console.log); 4. Create a document a. db.Models.Dib.create({ title: 'First Item', creator: 'Yay' }).then(console.log); 5. Find all documents again Connect to MongoDB: Let’s test it
  • 35. 1. Try and create a document that doesn’t pass validation. 2. Use the Mongoose method to find one document (hint http://mongoosejs.com/docs/queries.html) Connect to MongoDB: Let’s test it
  • 37. Set up our API server
  • 38. Set up our API open server/server.js
  • 40. const express = require('express'); const cors = require('cors'); const bodyParser = require('body-parser'); const PORT = process.env.PORT || 8080; const DOMAIN = process.env.DOMAIN || 'http://localhost' ; Set up our API: server.js
  • 41. function createServer() { const app = express(); app.use(cors(), bodyParser.json()); app.get('/', (req, res) => { res.send('Hello World!'); }); app.listen(PORT, () => { console.log(`Server ready at ${DOMAIN}:${PORT}/`); }); } createServer(); Set up our API: server.js
  • 42. 1. Start server a. node server.js 2. Open browser: http://localhost:8080/ 3. What do you see? Set up our API: Test It
  • 43. 1. Change a handler to return JSON to the browser 2. Add a new handler that says ‘Goodbye’ 3. Add a handler that takes in a parameter so we can say `Hello ${name}` (hint: https://expressjs.com/en/guide/routing.html) Set up our API: Exercise
  • 46. Create API endpoints # We want to expose our MongoDB data through an API # We’re going to expose all API methods under an /api route namespace. open server/api.js
  • 48. const express = require('express'); module.exports = function createApi({ Models }) { const api = express.Router(); // Get all Dibs api.get('/dibs', async (req, res) => { res.json({ data: await Models.Dib.find().sort('-createdAt'), }); }); Create API endpoints: api.js
  • 49. // Create a Dib api.post('/dibs', async (req, res) => { const { creator, title } = req.body; if (!creator || !title) { return res.status(500).json({ error: 'Must include a "creator" and a "title".', }); } res.json({ data: await Models.Dib.create({ creator , title, }), }); }); return api; }; Create API endpoints: api.js
  • 50. const db = require('./db'); const createApi = require('./api'); // inside createServer try { await db.connect(); } catch (error) { console.error(error.message); console.error('Closing server'); process.exit(1); } app.use('/api', createApi({ Models: db.Models })); Create API endpoints: server.js
  • 51. Check GET and browse to: http://localhost:8080/api/dibs Check POST with cURL curl --data '{"title": "Hello from Curl", "creator": "Mr. Curly"}' -X POST --header "Content-Type: application/json" http://localhost:8080/api/dibs Create API endpoints: Test It
  • 52. Create API endpoints: Catch Up https://github.com/hswolff/dibs/tree/tutori al/step2e/server
  • 54.
  • 55. Outline 1. Prerequisites 2. Create the Server a. Set up MongoDB b. Create server folder c. Connect to MongoDB d. Set up our API e. Create API endpoints 3. Create the Client a. Create client folder b. Connect to our API c. Render all dibs d. Add support for creating a dib e. Enable a user to log in 4. Let's call dibs a. Server support b. Client support 5. To real time, and beyond! a. Server support b. Client support
  • 58. Create client folder We used Create React App to scaffold our client
  • 59. Create client folder: Test It cd client npm start Does your browser open?
  • 61. Connect to our API open src/services/api.js
  • 63. Connect to our API: src/services/api.js const baseUrl = 'http://localhost:8080' ; function fetchWrapper(apiPath, options) { return fetch(`${baseUrl}/api${apiPath}`, options).then(res => res.json()); }
  • 64. export default { getDibs() { return fetchWrapper('/dibs'); }, createDib({ creator, title }) { return fetchWrapper('/dibs', { method: 'POST', headers: { 'content-type': 'application/json', }, body: JSON.stringify({ creator, title, }), }); }, }; Connect to our API: src/services/api.js
  • 65. 1. Ensure your API server is running. 2. Ensure your client environment is running. 3. Go to client/src/index.js. 4. We’re going to expose our client API globally. Connect to our API: Test It
  • 66. import api from './services/api'; window.api = api; Connect to our API: client/src/index.js
  • 67. 5. Go to your browser and open the Developer Tools (for Chrome go to View > Developer > Developer Tools) 6. Go to the “Console” tab 7. Type ‘api’ in the console. You should see your API code! 8. Exercise: Try making a request for “getDibs” Answer: api.getDibs().then(console.log) 9. Exercise: Try creating a new dib Answer: api.createDib({ creator: 'Browser', title: 'From the client!' }).then(console.log) Connect to our API: Test It
  • 68. Remove our debug code from index.js Connect to our API: Cleanup
  • 71. # We want to fetch our data from our server API # We’re going to load the data in our HomePage # We’re going to use React’s lifecycle methods to do so # Namely the componentDidMount lifecycle method open src/components/HomePage.js Render all dibs: Load the data
  • 73. import React, { Component } from 'react'; export default class HomePage extends Component { render() { return ( <div> <header> <h1>Got Dibs?</h1> </header> </div> ); } } Render all dibs: components/HomePage.js
  • 74. import React, { Component } from 'react'; import './App.css'; import HomePage from './components/HomePage'; class App extends Component { render() { return ( <div className="App-content"> <HomePage /> </div> ); } } export default App; Render all dibs: src/App.js
  • 75. .App-content { width: 600px; margin: 20px auto; } Render all dibs: src/App.css
  • 76. import React, { Component } from 'react'; import api from '../services/api'; export default class HomePage extends Component { state = { dibs: [], }; componentDidMount = async () => { const result = await api.getDibs(); this.setState({ dibs: result.data }); }; render() { const { dibs } = this.state; return ( <div> <header> <h1>Got Dibs?</h1> </header> <div> {dibs.map(dib => ( <pre key={dib._id}> {JSON.stringify(dib, null, 2)} </pre> ))} </div> </div> ); } Render all dibs: components/HomePage.js
  • 77. Render all dibs: Test It
  • 78. # Now we want to render each item a little better # To do so we’ll use the component “DibCell” open components/DibCell.js Render all dibs: With style!
  • 79. function LetsCode(){} Render all dibs: With style!
  • 80. import React, { Component } from 'react'; import './DibCell.css'; export default class DibCell extends Component { render() { const { title, creator } = this.props; return ( <div className="dib-container"> <div className="dib-left"> <div className="dib-creator"> <b>{creator}</b> is offering </div> <div className="dib-title">{title}</div> </div> <div className="dib-right" /> </div> ); } } Render all dibs: components/DibCell.js
  • 81. .dib-container { margin: 20px 0; padding: 20px 0; display: flex; } .dib-left { width: 70%; padding-right: 20px; margin-right: 20px; display: flex; flex-direction: column; justify-content: space-between; } .dib-creator { font-size: 0.9rem; } .dib-title { font-size: 2rem; } .dib-right { width: 30%; display: flex; flex-direction: column; justify-content: space-between; } Render all dibs: components/DibCell.css
  • 82. Render all dibs: components/HomePage.js import DibCell from './DibCell'; render() { const { dibs } = this.state; return ( <div> <header> <h1>Got Dibs?</h1> </header> <div>{dibs.map(dib => <DibCell key={dib._id} {...dib} />)}</div> </div> ); }
  • 83. Render all dibs: Test It
  • 86.
  • 87. BUT
  • 88.
  • 89. SO
  • 91. Add support for creating a dib
  • 92. # Using our CreateNewDib component # We need to hook it up to actually create the new dib. open src/components/CreateNewDib.js Add support for creating a dib
  • 93. function LetsCode(){} Add support for creating a dib
  • 94. import React, { Component } from 'react'; export default class CreateNewDib extends Component { state = { title: '', error: null, }; render() { const { error, title } = this.state; return ( <div> {error} <textarea autoFocus tabIndex={1} placeholder="Create New Dib" value={title} onChange={e => this.setState({ title: e.target.value })} /> <br /> <button>Create New Dib</button> </div> ); } } Add support for creating a dib: CreateNewDib
  • 95. import CreateNewDib from './CreateNewDib'; render() { const { dibs } = this.state; return ( <div> <header> <h1>Got Dibs?</h1> </header> <CreateNewDib /> <div>{dibs.map(dib => <DibCell key={dib._id} {...dib} />)}</div> </div> ); } Add support for creating a dib: HomePage
  • 96. import api from '../services/api'; <button onClick={this.createNew}>Create New Dib</button> createNew = async e => { e.preventDefault(); this.setState({ error: null }); try { await api.createDib({ title: this.state.title, creator: 'Fake Creator', }); this.setState({ title: '' }); this.props.onSuccess(); } catch (error) { this.setState({ error: error.message }); } }; Add support for creating a dib: CreateNewDib
  • 97. componentDidMount = () => { this.loadDibs(); }; loadDibs = async () => { const result = await api.getDibs(); this.setState({ dibs: result.data }); }; <CreateNewDib onSuccess={this.loadDibs} /> Add support for creating a dib: HomePage
  • 98. 1. Try creating a new dib! 2. Does your page refresh with the new dib? Add support for creating a dib: Test It
  • 99. 1. Style CreateNewDib UI 2. Add a button on the HomePage which shows and hides the CreateNewDib component Add support for creating a dib: Exercise
  • 101. Enable a user to log in
  • 102. Enable a user to log in # We need to enable a user to give us a username so we can show the right person that created a dib # We store the user in localStorage to persist it between refreshes # We’re going to use the SignIn component to let a user sign in. open src/components/SignIn.js
  • 104. import React, { Component } from 'react'; export default class SignIn extends Component { state = { input: '', }; logIn = () => { this.props.onUsernameChange(this.state.input); }; logOut = () => { this.props.onUsernameChange(null); }; render() { const { username } = this.props; const { input } = this.state; if (username) { return ( <div> Logged in as: < b>{username}</b> <button onClick={this.logOut}>Log Out</ button> </div> ); } return ( <div> <input value={input} onChange={e => this.setState({ input: e.target.value })} /> <button onClick={this.logIn}>Log In</button> </div> ); } } Enable a user to log in: SignIn.js
  • 105. import SignIn from './SignIn'; state = { dibs: [], username: localStorage.getItem('username'), }; onUsernameChange = username => { localStorage.setItem('username', username); this.setState({ username }); }; render() { const { dibs, username } = this.state; return ( <div> <header> <h1>Got Dibs?</h1> </header> <SignIn username={username} onUsernameChange={this.onUsernameChange} /> <br /> <CreateNewDib onSuccess={this.loadDibs} username={username} /> <div>{dibs.map(dib => <DibCell key={dib._id} {...dib} />)}</div> </div> ); Enable a user to log in: HomePage.js
  • 106. createNew = async e => { e.preventDefault(); this.setState({ error: null }); try { await api.createDib({ title: this.state.title, creator: this.props.username, }); this.setState({ title: '' }); this.props.onSuccess(); } catch (error) { this.setState({ error: error.message }); } }; Enable a user to log in: CreateNewDib.js
  • 107. 1. Try creating a new dib! 2. Do you see it appear? Enable a user to log in: Test it
  • 108. 1. Only show CreateNewDib if a username is set 2. Show an error if a user puts in an empty username 3. Style SignIn component Enable a user to log in: Exercise
  • 111.
  • 112. Outline 1. Prerequisites 2. Create the Server a. Set up MongoDB b. Create server folder c. Connect to MongoDB d. Set up our API e. Create API endpoints 3. Create the Client a. Create client folder b. Connect to our API c. Render all dibs d. Add support for creating a dib e. Enable a user to log in 4. Let's call dibs a. Server support b. Client support 5. To real time, and beyond! a. Server support b. Client support
  • 115. # We need to extend our Schema to support claiming a Dib Server support
  • 117. Server support: server/db.js const dibScheme = new mongoose.Schema( { title: { type: String, required: true, }, creator: { type: String, required: true, }, claimed: { // New user: String, time: Date, }, }, { timestamps: true } ); const Dib = mongoose.model('Dib', dibScheme);
  • 118. Server support # We need to add a new endpoint # Endpoint adds support for a user to claim a dib # We need to validate the data sent Need to make sure all data required is sent Need to make sure that the dib exists Need to make sure a dib has not already been claimed
  • 120. // Claim a Dib api.put('/dibs/:dibId', async (req, res) => { const { dibId } = req.params; const { user } = req.body; if (!user) { return res.status(500).json({ error: 'No "user" given to claim Dib.', }); } let dib; try { dib = await Models.Dib.findById(dibId); } catch (error) { return res.status(500).json({ error: 'Cannot find Dib with given id', }); } Server support: server/api.js if (dib.claimed.user) { return res.status(500).json({ error: 'Dib has already been claimed!', }); } dib.claimed.user = user; dib.claimed.time = new Date(); res.json({ data: await dib.save(), }); });
  • 121. Server support: Catch Up https://github.com/hswolff/dibs/tree/tuto rial/step4/server
  • 123. # Add a new method to our API service to call our new API endpoint called “claimDib” Client support
  • 125. Client support: client/src/services/api.js claimDib({ id, user }) { return fetchWrapper(`/dibs/${id}`, { method: 'PUT', headers: { 'content-type' : 'application/json' , }, body: JSON.stringify({ user, }), }); },
  • 126. # Add a handler to actually make our API call to claim a dib # Update our “Dibs?” text to say “Claimed!” if the dib is already taken open src/components/DibCell.js Client support
  • 128. .dib-claim-button { height: 100%; width: 100%; font-size: 50px; cursor: pointer; } Client support: client/src/DibCell.js const { title, creator, claimed } = this.props; const isClaimed = claimed && claimed.user != null; return ( <div className="dib-container"> <div className="dib-left"> <div className="dib-creator"> <b>{creator}</b> is offering </div> <div className="dib-title">{title}</div> </div> <div className="dib-right"> <button className="dib-claim-button"> {isClaimed ? 'Claimed!' : 'Dibs?'} </button> </div> </div> );
  • 129. Client support: client/src/DibCell.js <button className="dib-claim-button" onClick={this.claimDib}> {isClaimed ? 'Claimed!' : 'Dibs?'} </button> claimDib = async () => { this.setState({ error: null }); try { await api.claimDib({ id: this.props._id, user: this.props.username, }); } catch (error) { console.error('Error claiming dib', error); } };
  • 130. Client support: client/src/HomePage.js <div> {dibs.map(dib => ( <DibCell key={dib._id} {...dib} username={username} /> ))} </div>
  • 131. 1. Try claiming a dib! 2. Refresh the page 3. Does it show that it’s claimed? Client support: Try It
  • 132. 1. Show an error if a dib has already been claimed 2. Disable the button if a user is not logged in Client support: Exercise
  • 134. Guess what we got?
  • 135.
  • 136. Outline 1. Prerequisites 2. Create the Server a. Set up MongoDB b. Create server folder c. Connect to MongoDB d. Set up our API e. Create API endpoints 3. Create the Client a. Create client folder b. Connect to our API c. Render all dibs d. Add support for creating a dib e. Enable a user to log in 4. Let's call dibs a. Server support b. Client support 5. To real time, and beyond! a. Server support b. Client support
  • 137. To real time, and beyond!
  • 139. # We want to open a Change Stream to be notified of when our collection in MongoDB changes # Change Streams are a new feature in MongoDB 3.6 # Change Streams allow applications to access real-time data changes without the complexity and risk of tailing the oplog. (docs) Server support
  • 141. Server support: db.js async function connect() { await mongoose.connect(dbUri); console.log('Connected to MongoDB'); const dibChangeStream = Models.Dib.collection.watch({ fullDocument: 'updateLookup', }); dibChangeStream.on('change', result => { console.log(JSON.stringify(result, null, 2)); }); }
  • 142. # Try making a new dib! # Try claiming a dib! # Should see output from your server. Server support: Test Change Stream
  • 143. So let’s talk real time. We want our updates to show immediately. There’s one technology good for that… WebSockets!
  • 144. WebSockets are an advanced technology that makes it possible to open an interactive communication session between the user's browser and a server. With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply. - https://developer.mozilla.org/en-US/docs/Web/API/WebSockets _API
  • 145. # We’re using socket.io as our WebSocket server # Create our WebSocket server Server support
  • 147. Server support: server.js const http = require('http'); const socketIo = require('socket.io'); // ... const httpServer = http.Server(app); const io = socketIo(httpServer); // ... await db.connect(io); // ... httpServer.listen(PORT, () => { console.log(`Server ready at ${DOMAIN}:${PORT}/`); });
  • 148. # Now we want to share those changes to the client # And we’ll do that through our WebSocket Server support
  • 150. Server support: db.js async function connect(io) { await mongoose.connect(dbUri); console.log('Connected to MongoDB'); const dibChangeStream = Models.Dib.collection.watch({ fullDocument: 'updateLookup', }); dibChangeStream.on('change', result => { io.emit('dib changeEvent', { type: result.operationType, dib: { claimed: {}, ...result.fullDocument, id: result.fullDocument._id, }, }); }); }
  • 153. # We need to be able to connect to our WebSocket server # To do that we’ll use… # socket.io on the client! Client support
  • 154. # Let’s add a method for us to connect to our WebSocket server # In particular we want to subscribe to our ‘dib changeEvent’ # When that event happens we want our callback to be called open src/services/api.js Client support
  • 156. Client support: client/src/services/api.js import io from 'socket.io-client'; function createSocket() { const socket = io(baseUrl); return socket; } subscribeToDibChanges(cb) { createSocket().on('dib changeEvent', cb); },
  • 157. # Now let’s actually subscribe to the WebSocket # We’ll update our UI when a new event comes in Client support
  • 159. componentDidMount = () => { this.loadDibs(); api.subscribeToDibChanges (event => { const { dib, type } = event; const currentDibs = this.state.dibs; if (type === 'update') { return this.setState({ dibs: [ ... currentDibs .map(prevDib => { if (prevDib._id === dib._id) { return dib; } return prevDib; }), ], }); } // If adding a new dib return this.setState({ dibs: [dib, ...currentDibs], }); }); }; Client support: components/HomePage.js
  • 160. 1. Open another browser in Incognito 2. Try making a new dib. 3. Do you see it show up in the other browser?? Client support: Test it!
  • 163.
  • 165.
  • 166. Outline 1. Prerequisites 2. Create the Server a. Set up MongoDB b. Create server folder c. Connect to MongoDB d. Set up our API e. Create API endpoints 3. Create the Client a. Create client folder b. Connect to our API c. Render all dibs d. Add support for creating a dib e. Enable a user to log in 4. Let's call dibs a. Server support b. Client support 5. To real time, and beyond! a. Server support b. Client support
  • 168. 1. Instantiated our own local MongoDB 2. Created an entire API server, powered by Express 3. Opened a MongoDB Change Stream 4. Created a WebSocket server that tells the client when data in our MongoDB Change Stream changed 5. Created a React application 6. Connected to our API server on the client 7. Added the ability to list all our dibs 8. Added the ability to create a dib 9. Added the ability to claim a dib 10. ...and we made it all work in real time! Let’s Recap
  • 169.
  • 170.
  • 171.
  • 173. 1. Location of Dib. 2. Price/bounty of Dib. 3. Auth with Google 4. Real-time comments on a Dib 5. Able to edit Dibs that you created. 6. Able to un-claim a Dib if you're the creator of the dib. 7. ...and more! Take it further
  • 174. Got Dibs? Building a Real-Time Bidding App with Change Streams A tutorial by Harry Wolff
  • 175. Harry Wolff Lead Engineer, MongoDB @hswolff TheConsoleLog.com