Integração do Change Streams do MongoDB com Socket.IO
Avalie esse Tutorial
O guia de IntroduçãodoSocket.IO fornece uma boa introdução ao Socket.IO. O guia agrupa o servidor e o cliente em um único aplicativo, onde as mensagens enviadas por meio de um formulário de entrada HTML são recebidas e exibidas na página.
Como o MongoDB oferece suporte a uma estrutura de eventosexcepcional própria, este tutorial demonstrará como propagar eventos emitidos do MongoDB por meio do Socket.IO. Para manter as coisas consistentes, tentarei espelhar o guia de Introdução ao Socket.IO o máximo possível.
Vamos começar...
Assim como no guia de Introdução do Socket.IO, vamos configurar uma página da Web HTML simples; no entanto, em nosso exemplo, ela só exibirá uma lista de mensagens -- não haverá formulário de entrada.
Primeiro, vamos criar um arquivo de manifesto
package.json
que descreve nosso projeto. Recomendamos que você o coloque em um diretório vazio dedicado (chamarei demongo-socket-chat-example
).1 { 2 "name": "monngo-socket-chat-example", 3 "version": "0.0.1", 4 "description": "my first mongo socket.io app", 5 "dependencies": {} 6 }
Em seguida, use
npm
para instalar express
:1 npm install express@4
One Express está instalado, podemos configurar um arquivo
index.js
que configurará nosso aplicativo.1 const express = require('express'); 2 const app = express(); 3 const http = require('http'); 4 const server = http.createServer(app); 5 6 app.get('/', (req, res) => { 7 res.send('<h1>Hello world</h1>'); 8 }); 9 10 server.listen(3000, () => { 11 console.log('listening on *:3000'); 12 });
Isso significa que:
- O Express inicializa o
app
para ser um manipulador de função que você pode fornecer a um servidor HTTP (como visto na linha 4). - Definimos um manipulador de rota / que é chamado quando acessamos nosso site inicial.
- Fazemos o servidor HTTP escutar na porta 3000.
Se você executar
node index.js
, verá o seguinte:Até agora, em
index.js
, estamos chamando res.send
e passando uma string de HTML. Nosso código pareceria muito confuso se apenas colocássemos todo o HTML do aplicativo lá, então vamos criar um arquivoindex.html
e exibi-lo.Vamos refatorar nosso manipulador de rota para usar
sendFile
em vez disso.1 app.get('/', (req, res) => { 2 3 res.sendFile(__dirname + '/index.html'); 4 5 });
Aqui está um arquivo
index.html
simples para exibir uma lista de mensagens com alguns estilos incluídos:1 2 <html> 3 <head> 4 <title>Socket.IO chat</title> 5 <style> 6 body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } 7 8 #messages { list-style-type: none; margin: 0; padding: 0; } 9 #messages > li { padding: 0.5rem 1rem; } 10 #messages > li:nth-child(odd) { background: #efefef; } 11 </style> 12 </head> 13 <body> 14 <h1>Hello world from file</h1> 15 <ul id="messages"></ul> 16 </body> 17 </html>
Se você reiniciar o processo (pressionando Control+C e executando
node index.js
novamente) e atualizar a página, ela deverá ficar assim:Como você está aqui, estou presumindo que você já tem acesso a um cluster MongoDB. Caso contrário, basta seguir estas instruçõesCriar um cluster MongoDB .
Observe que um cluster (conjunto de réplicas) é necessário porque usaremos change stream, que exigem um oplog. No entanto, não há necessidade de se preocupar, pois é fácil configurar um único conjunto de réplicas de nó.
Para este exemplo, criarei um banco de dados
chat
com uma coleçãomessages
junto com um registro inicial que usarei posteriormente para validar a conectividade com o MongoDB do meu aplicativo cliente:Para evitar o armazenamento de credenciais do MongoDB em nosso código de aplicativo, usaremos dotenv para ler a connection string do MongoDB de nosso ambiente. Assim como no framework
express
, use o npm para instalar o dotenv
:1 npm install dotenv --save
Crie um arquivo
.env
com a seguinte variávelMONGODB_CONNECTION_STRING
:1 MONGODB_CONNECTION_STRING='<Your MongoDB Connection String>'
Em seguida, adicione o seguinte ao seu
index.js
:1 require('dotenv').config() 2 console.log(process.env.MONGODB_CONNECTION_STRING) // remove this after you've confirmed it working
Se você reiniciar o processo (pressionando Control+C e executando
node index.js
novamente), poderá verificar se seu ambiente está funcionando corretamente:Use o npm mais uma vez para instalar o driver Node.js:
1 npm install mongodb@4.5
Adicione o seguinte código ao seu
index.js
:1 const { MongoClient } = require("mongodb"); 2 3 const client = new MongoClient(process.env.MONGODB_CONNECTION_STRING); // remove this after you've confirmed it working 4 5 async function run() { 6 7 try { 8 9 await client.connect(); 10 const database = client.db('chat'); 11 const messages = database.collection('messages'); 12 13 // Query for our test message: 14 const query = { message: 'Hello from MongoDB' }; 15 const message = await messages.findOne(query); 16 console.log(message); 17 18 } catch { 19 20 // Ensures that the client will close when you error 21 await client.close(); 22 } 23 } 24 25 run().catch(console.dir);
Reinicie seu aplicativo e você deverá ver o seguinte
Para obter mais informações, este Quick Start do MongoDB Node.js fornece uma excelente introdução à incorporação do MongoDB em seus aplicativos Node.js.
Queremos ser alertados sempre que uma nova mensagem for inserida no banco de dados. Para fins deste tutorial, também observaremos as atualizações de mensagens. Substitua as três linhas do código de teste de query em
index.js
pelo seguinte:1 // open a Change Stream on the "messages" collection 2 changeStream = messages.watch(); 3 4 // set up a listener when change events are emitted 5 changeStream.on("change", next => { 6 // process any change event 7 switch (next.operationType) { 8 case 'insert': 9 console.log(next.fullDocument.message); 10 break; 11 case 'update': 12 console.log(next.updateDescription.updatedFields.message); 13 } 14 });
Em seguida, edite e/ou insira algumas mensagens:
Socket.IO é composto de duas partes:
- Um servidor que se integra (ou é montado) no Node.JS HTTP Server socket.io
- Uma biblioteca de cliente que carrega no lado do navegador socket.io-client
Durante o desenvolvimento, o
socket.io
atende ao cliente automaticamente para nós, como vamos ver, então, por enquanto, só precisamos instalar um módulo:1 npm install socket.io
Isso instalará o módulo e adicionará a dependência a
package.json
. Agora vamos editar index.js
para adicioná-lo:1 const { Server } = require("socket.io"); 2 const io = new Server(server);
Agora, em
index.html
, adicione o seguinte snippet antes de </body>
(tag de fim de corpo):1 <script src="/socket.io/socket.io.js"></script> 2 <script> 3 var socket = io(); 4 </script>
O próximo objetivo é emitir o evento do servidor para o resto dos usuários.
Para enviar um evento para todos, o Socket.io nos fornece o
io.emit()
método , que tem a seguinte aparência:1 io.emit('<event name>', '<event data>')
Então, aumente nosso código de fluxo de alterações com o seguinte:
1 switch (next.operationType) { 2 case 'insert': 3 io.emit('chat message', next.fullDocument.message); 4 console.log(next.fullDocument.message); 5 break; 6 7 case 'update': 8 io.emit('chat message', next.updateDescription.updatedFields.message); 9 console.log(next.updateDescription.updatedFields.message); 10 }
E, no lado do cliente , quando capturarmos um evento de "mensagem de chat", nós o incluiremos na página. O código JavaScripttotal do lado do cliente agora equivale a:
1 2 <html> 3 <head> 4 <title>Socket.IO chat</title> 5 <style> 6 body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } 7 8 #messages { list-style-type: none; margin: 0; padding: 0; } 9 #messages > li { padding: 0.5rem 1rem; } 10 #messages > li:nth-child(odd) { background: #efefef; } 11 </style> 12 </head> 13 <body> 14 <ul id="messages"></ul> 15 16 <script src="/socket.io/socket.io.js"></script> 17 <script> 18 var socket = io(); 19 var messages = document.getElementById('messages'); 20 21 socket.on('chat message', function(msg) { 22 var item = document.createElement('li'); 23 item.textContent = msg; 24 messages.appendChild(item); 25 window.scrollTo(0, document.body.scrollHeight); 26 }); 27 </script> 28 </body> 29 </html>
E isso conclui nosso aplicativo de chat em cerca 80 linhas de código! É assim que ele aparece no cliente web quando as mensagens são inseridas ou atualizadas em nossa
chat.messages
collection em MongoDB: