Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Junte-se a nós no Amazon Web Services re:Invent 2024! Saiba como usar o MongoDB para casos de uso de AI .
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Idiomaschevron-right
JavaScriptchevron-right

Integre o MongoDB às funções do Vercel para a experiência sem servidor

Nic Raboy7 min read • Published Jun 28, 2022 • Updated Sep 09, 2024
Next.jsNode.jsJavaScript
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
{ Você está trabalhando com o Functions as a Service (FaaS), geralmente chamado de serverless, mas não consegue fazer seu banco de dados funcionar? Dada a natureza dessas funções sem servidor, interagir com um banco de dados é uma experiência um pouco diferente do que se você fosse criar seu próprio back-end totalmente hospedado.
Por que é uma experiência diferente, embora?
Os bancos de dados em geral, não apenas o MongoDB, podem ter uma quantidade finita de conexões simultâneas. Quando você hospeda seu próprio aplicativo da web, esse aplicativo normalmente se conecta ao seu banco de dados uma vez e enquanto o aplicativo estiver em execução, o mesmo acontece com a conexão com o banco de dados. No entanto, as funções oferecem uma experiência diferente. Em vez de um aplicativo sempre disponível, agora você está trabalhando com um aplicativo que pode ou não estar disponível no momento da solicitação para economizar recursos. Se você tentar se conectar ao seu banco de dados em sua lógica de função, correrá o risco de muitas conexões. Se a função desligar, hibernar ou semelhante, você correrá o risco de que sua conexão com o banco de dados não esteja mais disponível.
Neste tutorial, vamos ver como usar o driverdoMongoDB Node.js com funções do Vercel, algo bastante comum ao desenvolver aplicativos Next.js.

Os requisitos

Há alguns requisitos que devem ser atendidos antes de começar a usar este tutorial, dependendo de até onde você deseja ir.
  • Você deve ter um MongoDB Atlas cluster implantado, camada grátis (M0) ou melhor.
  • Você deve ter uma conta do Vercel se quiser implantar na produção.
  • Uma versão recente do Node.js e NPM deve estar disponível.
Neste tutorial, não vamos distribuir para a produção. Tudo o que planejamos fazer pode ser testado localmente, mas se você quiser implantar, precisará de uma conta no Vercel e da CLI instalada e configurada ou do seu hostGit . Ambos estão fora do escopo deste tutorial.
Embora entraremos em detalhes do MongoDB Atlas mais tarde neste tutorial, você já deve ter uma conta do MongoDB Atlas e um cluster implantado. Se precisar de ajuda com qualquer um deles, considere conferir este tutorial.
A grande coisa que você precisará é o Node.js. Nós o usaremos para desenvolver e testar nosso aplicativo Next.js.

Criando um novo aplicativo Next.js com a CLI

Criar um novo projeto Next.js é fácil quando se trabalha com a CLI. Em uma linha de comando, supondo que o Node.js esteja instalado, execute o seguinte comando:
1npx create-next-app@latest
Você será solicitado a fornecer algumas informações que resultarão na criação do seu projeto. A qualquer momento deste tutorial, você pode executar npm run dev para criar e atender seu aplicativo localmente. Você também poderá testar suas funções do Vercel!
Antes de prosseguirmos, vamos adicionar a dependência do driver MongoDB Node.js:
1yarn add mongodb
Não vamos explorá-lo neste tutorial, mas o Vercel oferece um modelo inicial com a integração do MongoDB Atlas já configurada. Se você quiser saber mais, confira o tutorial de Jesse Hall: How to Connect MongoDB Atlas to Vercel usando a nova integração. Em vez disso, vamos ver como fazer as coisas manualmente para ter uma ideia do que está acontecer em cada estágio do ciclo de desenvolvimento.

Configurando um cluster de banco de dados no MongoDB Atlas

Neste ponto, você já deve ter uma conta do MongoDB Atlas com um projeto e cluster criados. O nível gratuito é adequado para este tutorial.
Em vez de usar nossa mente para criar um novo conjunto de dados para esse exemplo, vamos usar um dos bancos de dados de amostra disponíveis para os usuários do MongoDB.
Carregar um conjunto de dados de amostra do MongoDB
Carregar um conjunto de dados de amostra do MongoDB
No painel do MongoDB Atlas, clique no menu de reticências de um dos clusters e, em seguida, escolha carregar os conjuntos de dados de amostra. Pode levar alguns minutos, então dê algum tempo.
Para este tutorial, usaremos o banco de dadossample_restaurants, mas, na verdade, isso não importa, pois o foco deste tutorial é a instalação e a configuração, e não os dados reais.
Com o conjunto de dados de amostra carregado, Go e crie um novo usuário na aba "Acesso ao banco de dados" do painel, seguido pela adição de seu IP às regras de "Acesso à rede". Você precisará fazer isso para se conectar ao MongoDB Atlas a partir do seu aplicativo Next.js. Se você optar por implantar seu aplicativo, precisará adicionar uma regra 0.0.0.0de acordo com adocumentação do Vercel.

Conecte-se ao MongoDB e conexões de cache para uma experiência otimizada para desempenho

Next.js é uma dessas tecnologias em que existem algumas maneiras de resolver o problema. Poderemos interagir com o MongoDB no tempo de construção, criando um site 100% gerado estático, mas há muitos motivos pelos quais podemos querer manter as coisas adhoc em uma função sem servidor.
Dentro do seu projeto Next.js, crie um .env.local arquivo com as seguintes variáveis:
1NEXT_ATLAS_URI=YOUR_ATLAS_URI_HERE
2NEXT_ATLAS_DATABASE=sample_restaurants
3NEXT_ATLAS_COLLECTION=restaurants
Lembre-se de que estamos usando o banco de dadossample_restaurants neste exemplo, mas você pode ser ousado e usar o que quiser. Não se lembre de trocar as informações de conexão no arquivo.env.local pelas suas.
Em seguida, crie um arquivolib/mongodb.js em seu projeto. É aqui que trataremos das etapas reais de conexão. Preencha o arquivo com o seguinte código:
1import { MongoClient } from "mongodb";
2
3const uri = process.env.NEXT_ATLAS_URI;
4const options = {
5 useUnifiedTopology: true,
6 useNewUrlParser: true,
7};
8
9let mongoClient = null;
10let database = null;
11
12if (!process.env.NEXT_ATLAS_URI) {
13 throw new Error('Please add your Mongo URI to .env.local')
14}
15
16export async function connectToDatabase() {
17 try {
18 if (mongoClient && database) {
19 return { mongoClient, database };
20 }
21 if (process.env.NODE_ENV === "development") {
22 if (!global._mongoClient) {
23 mongoClient = await (new MongoClient(uri, options)).connect();
24 global._mongoClient = mongoClient;
25 } else {
26 mongoClient = global._mongoClient;
27 }
28 } else {
29 mongoClient = await (new MongoClient(uri, options)).connect();
30 }
31 database = await mongoClient.db(process.env.NEXT_ATLAS_DATABASE);
32 return { mongoClient, database };
33 } catch (e) {
34 console.error(e);
35 }
36}
Pode não parecer muito, mas muitas coisas importantes estão acontecendo no arquivo acima, específicas para Next.js e funções sem servidor. Especificamente, dê uma olhada na funçãoconnectToDatabase:
1export async function connectToDatabase() {
2 try {
3 if (mongoClient && database) {
4 return { mongoClient, database };
5 }
6 if (process.env.NODE_ENV === "development") {
7 if (!global._mongoClient) {
8 mongoClient = await (new MongoClient(uri, options)).connect();
9 global._mongoClient = mongoClient;
10 } else {
11 mongoClient = global._mongoClient;
12 }
13 } else {
14 mongoClient = await (new MongoClient(uri, options)).connect();
15 }
16 database = await mongoClient.db(process.env.NEXT_ATLAS_DATABASE);
17 return { mongoClient, database };
18 } catch (e) {
19 console.error(e);
20 }
21}
O objetivo da função acima é fornecer-nos uma conexão de cliente para trabalhar, bem como um banco de dados. No entanto, os detalhes mais refinados sugerem que só precisamos estabelecer uma nova conexão se não existir uma e não enviar spam para nosso banco de dados com conexões se estivermos no modo de desenvolvimento para Next.js. O servidor de desenvolvimento local se comporta de forma diferente da que você teria na produção, por isso a necessidade de verificar.
Lembre-se, as quantidades de conexão são finitas e só devemos nos conectar se ainda não estivermos conectados.
Então, o que estamos fazendo na função é que primeiro verificamos se essa conexão existe. Em caso afirmativo, retorne-o e permita que o que estiver chamando a função use essa conexão. Se a conexão não existir e estivermos no modo de desenvolvimento, verificamos se temos uma sessão em cache e a usamos, se tivermos. Caso contrário, precisamos criar uma conexão e armazená-la em cache para o modo de desenvolvimento ou produção.
Se você entender alguma coisa do código acima, entenda que estamos apenas criando conexões se as conexões ainda não existirem.

Executando queries do MongoDB a partir de uma função do Vercel no aplicativo Next.js

Já fizemos a parte difícil. Temos um sistema de gerenciamento de conexões em vigor para o MongoDB ser usado em todo o nosso aplicativo Vercel. A próxima parte envolve a criação de endpoints de API, de forma quase idêntica ao Express Framework, e consumi-los a partir do frontend do Next.js.
Então, com o que isso se parece exatamente?
Em seu projeto, crie um arquivopages/api/list.js com o seguinte código JavaScript:
1import { connectToDatabase } from "../../lib/mongodb";
2
3export default async function handler(request, response) {
4
5 const { database } = await connectToDatabase();
6 const collection = database.collection(process.env.NEXT_ATLAS_COLLECTION);
7
8 const results = await collection.find({})
9 .project({
10 "grades": 0,
11 "borough": 0,
12 "restaurant_id": 0
13 })
14 .limit(10).toArray();
15
16 response.status(200).json(results);
17
18}
As funções do Vercel existem no diretóriopages/api. Neste caso, estamos criando uma função com o objetivo de listar dados. Especificamente, vamos listar dados de restaurantes.
Em nosso código acima, estamos aproveitando a funçãoconnectToDatabasede nosso código de gerenciamento de conexão. Quando executamos a função, estamos obtendo uma conexão sem nos preocuparmos se precisamos criar ou reutilizar uma. O código da função subjacente cuida disso para nós.
Com uma conexão, podemos encontrar todos os documentos dentro de uma coleção. Nem todos os campos são importantes para nós, então estamos usando uma projeção para excluir o que não queremos. Em vez de retornar todos os documentos dessa grande coleção, estamos limitando os resultados a apenas alguns.
Os resultados são retornados para qualquer código ou cliente externo que os solicite.
Se quiséssemos consumir o endpoint de dentro do aplicativo Next.js, poderíamos fazer algo como o seguinte no arquivopages/index.js:
1import { useEffect, useState } from "react";
2import Head from 'next/head'
3import Image from 'next/image'
4import styles from '../styles/Home.module.css'
5
6export default function Home() {
7
8 const [restaurants, setRestaurants] = useState([]);
9
10 useEffect(() => {
11 (async () => {
12 const results = await fetch("/api/list").then(response => response.json());
13 setRestaurants(results);
14 })();
15 }, []);
16
17 return (
18 <div className={styles.container}>
19 <Head>
20 <title>Create Next App</title>
21 <meta name="description" content="Generated by create next app" />
22 <link rel="icon" href="/favicon.ico" />
23 </Head>
24
25 <main className={styles.main}>
26 <h1 className={styles.title}>
27 MongoDB with <a href="https://nextjs.org">Next.js!</a> Example
28 </h1>
29 <br />
30 <div className={styles.grid}>
31 {restaurants.map(restaurant => (
32 <div className={styles.card} key={restaurant._id}>
33 <h2>{restaurant.name}</h2>
34 <p>{restaurant.address.street}</p>
35 </div>
36 ))}
37 </div>
38 </main>
39 </div>
40 )
41}
Ignorando o código Next.js clichê, adicionamos um useState e useEffect como o seguinte:
1const [restaurants, setRestaurants] = useState([]);
2
3useEffect(() => {
4 (async () => {
5 const results = await fetch("/api/list").then(response => response.json());
6 setRestaurants(results);
7 })();
8}, []);
O código acima consumirá a API quando o componente carregar. Podemos então renderizá-lo na seção a seguir:
1<div className={styles.grid}>
2 {restaurants.map(restaurant => (
3 <div className={styles.card} key={restaurant._id}>
4 <h2>{restaurant.name}</h2>
5 <p>{restaurant.address.street}</p>
6 </div>
7 ))}
8</div>
Não há nada fora do comum acontecendo no processo de consumo ou renderização. O trabalho pesado que era importante estava na própria função, bem como em nosso arquivo de gerenciamento de conexões.

Conclusão

Você acabou de ver como usar o MongoDB Atlas com funções do Vercel, que é uma solução sem servidor que exige um tipo de abordagem diferente. Lembre-se, ao lidar com serverless, a disponibilidade de suas funções está no ar. Você não quer gerar muitas conexões e não quer tentar usar conexões que não existem. Resolvemos isso armazenando nossas conexões em cache e usando a conexão em cache, se disponível. Caso contrário, crie uma nova conexão.
Tem alguma dúvida ou acha que pode melhorar esta solução? Compartilhe-o nos MongoDB Community!

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Início rápido

Como usar transações MongoDB em Node.js


Aug 24, 2023 | 10 min read
Tutorial

Criar um backend de gerenciamento de mídia escalável: integrando Node.js, Armazenamento de blobs Azure e MongoDB


Nov 05, 2024 | 10 min read
Tutorial

Introdução ao Deno 2.0 e MongoDB


Oct 22, 2024 | 13 min read
Tutorial

Adicione memória ao seu aplicativo JavaScript RAG usando MongoDB e LangChain


Sep 18, 2024 | 9 min read
Sumário