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
Produtoschevron-right
Atlaschevron-right

Mostrando visualmente os destaques do Atlas Search com JavaScript e HTML

Nic Raboy7 min read • Published Jan 31, 2022 • Updated Feb 03, 2023
Node.jsAtlasPesquisaJavaScript
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Quandose trata de encontrar palavras ou frases específicas no texto, você provavelmente vai querer usar uma opção de pesquisa em linguagem natural, como a pesquisa de texto completo (FTS). É claro que você poderia criar um conjunto de expressões regulares complicado e difícil de manter para pesquisar no texto, mas essa é uma opção que a maioria dos desenvolvedores não deseja. Isso sem falar que não abrangerá todo o escopo do que um processador de linguagem natural normalmente realiza.
Em um tutorial anterior intitulado Construindo um elemento de formulário de preenchimento automático com Atlas Search e JavaScript, escrevi sobre a pesquisa de receitas à medida que são digitadas no MongoDB Atlas usando o operadorautocomplete . Embora este tutorial tenha feito o trabalho muito bem, ele não detalhou o que exatamente estava sendo correspondido para qualquer termo específico.
Neste tutorial, vamos ver como usar o Atlas Search e trabalhar com os dados de destaque para mostrar visualmente quaisquer correspondências nos termos em um aplicativo voltado para o usuário. O destaque é uma ferramenta poderosa da Pesquisa para permitir que os usuários encontrem o texto exato que desejam em seu contexto adequado.
Para ter uma ideia do que planejamos realizar, dê uma olhada na seguinte imagem animada:
Realce do Atlas Search
No cenário acima, estamos pesquisando mensagens em uma sala de bate-papo. Quando inserimos um termo no Atlas Search, obtemos as mensagens de bate-papo em resposta, com quaisquer acertos em potencial destacados. Os possíveis acertos podem corresponder exatamente ou podem ter um determinado nível de imprecisão que exploraremos. Neste exemplo específico, o número de respostas destacadas é limitado a cinco.

Definir um modelo de dados para pesquisar e criar um índice de pesquisa

Antes de entrarmos diretamente na criação do back-end para pesquisa e do front-end para exibição, precisamos ter uma ideia do nosso modelo de dados. Vamos supor que estamos trabalhando com dados de bate-papo do usuário e queremos pesquisar determinadas palavras e frases. Com isso em mente, nossos documentos poderiam ficar assim:
1{
2 "_id": "mongodb",
3 "messages": [
4 {
5 "sender": "nraboy",
6 "message": "Hello World"
7 }
8 ]
9}
O exemplo de documento acima não é o mais realista, mas nos dá alguma coisa. Toda vez que uma nova mensagem é adicionada à sala de bate-papo, ela é anexada ao arraymessagescom as informações do remetente associado. Poderíamos tornar isso muito mais complexo, mas não é necessário para este exemplo.
O próximo passo é criar um índice de pesquisa padrão em nossa collection de dados. Para este exemplo, usaremos um banco de dadosgamedev e uma collectionchats.
criar um índice do atlas search
Embora possamos criar um índice específico para os campos que estamos planejando usar, por questões de simplicidade, a criação de um índice dinâmico padrão será mais do que suficiente. Para fazer isso, basta clicar no botão verde Criar Índice do Atlas Search. Vamos aceitar as configurações padrão e clicar em Criar índice. Isso nos fornecerá o índice padrão com a seguinte configuração:
1{
2 "mappings": {
3 "dynamic": true
4 }
5}
O analisadorlucene.standard é o analisador padrão para o Atlas Search e mais informações sobre ele podem ser encontradas na documentação.

Desenvolvendo o backend movido a Atlas Search e Express com Node.js

Neste exemplo, precisaremos de um back-end para lidar com a interação com o banco de dados para pesquisa. Para manter a pilha consistente neste exemplo, vamos usar o Node.js com algumas dependências comuns.
Crie um novo diretório em seu computador e, na linha de comando, execute o seguinte:
1npm init -y
2npm install express mongodb cors --save
Os comandos acima criarão um novo arquivopackage.json e baixarão o Express Framework, o driver Node.js do MongoDB e um middleware de compartilhamento de recursos entre origens que nos permitirá acessar nosso back-end a partir do front-end operando em uma porta diferente.
No mesmo diretório do projeto, crie um arquivomain.js e adicione o seguinte código padrão do Express Framework com MongoDB:
1const { MongoClient, ObjectID } = require("mongodb");
2const Express = require("express");
3const Cors = require("cors");
4const { request } = require("express");
5
6const client = new MongoClient(process.env["ATLAS_URI"]);
7const server = Express();
8
9server.use(Cors());
10
11var collection;
12
13server.get("/search", async (request, response) => { });
14
15server.listen("3000", async () => {
16 try {
17 await client.connect();
18 collection = client.db("gamedev").collection("chats");
19 } catch (e) {
20 console.error(e);
21 }
22});
No código acima, estamos importando cada uma de nossas dependências e inicializando o Express Framework, bem como o MongoDB. O ATLAS_URI no exemplo acima deve ser armazenado como uma variável de ambiente em seu computador. Você pode obtê-la no painel do MongoDB Atlas e ela terá a seguinte aparência:
1mongodb+srv://<username>:<password>@cluster0-yyarb.mongodb.net/<dbname>?retryWrites=true&w=majority
Claro, não use meu exemplo acima porque você precisará usar suas próprias informações de cluster. Para obter ajuda para começar a usar o MongoDB Atlas, confira meu tutorial anterior sobre o assunto.
Observe a seção do código em que estamos ouvindo as conexões:
1server.listen("3000", async () => {
2 try {
3 await client.connect();
4 collection = client.db("gamedev").collection("chats");
5 } catch (e) {
6 console.error(e);
7 }
8});
No código acima, estamos nos conectando ao cluster especificado do MongoDB Atlas e estamos obtendo um identificador para a coleção chatsno banco de dadosgamedev. Sinta-se à vontade para usar sua própria coleção e nomeação de banco de dados, mas observe que este exemplo seguirá o modelo de dados definido anteriormente no que se refere à pesquisa.
Com o boilerplate em vigor, vamos pular para o endpoint/search que está atualmente vazio. Em vez disso, vamos querer alterá-lo para o seguinte:
1server.get("/search", async (request, response) => {
2 try {
3 let result = await collection.aggregate([
4 {
5 "$search": {
6 "text": {
7 "query": `${request.query.term}`,
8 "path": "messages.message",
9 "fuzzy": {
10 "maxEdits": 2
11 }
12 },
13 "highlight": {
14 "path": "messages.message"
15 }
16 }
17 },
18 {
19 "$addFields": {
20 "highlights": {
21 "$meta": "searchHighlights"
22 }
23 }
24 }
25 ]).toArray();
26 response.send(result);
27 } catch (e) {
28 response.status(500).send({ message: e.message });
29 }
30});
No código de endpoint acima, estamos criando um pipeline de agregação.
Como planejamos usar o Atlas Search, o operador$search precisa ser o primeiro estágio no pipeline. Neste primeiro estágio, estamos pesquisando em torno de um termo fornecido. Em vez de pesquisar o documento inteiro, estamos pesquisando dentro do objeto messageda array messages . O campofuzzy com um maxEdits de 2 define o número de edições de caracteres únicos necessárias para corresponder ao termo de pesquisa especificado. Por exemplo, se inserirmos hlo, podemos obter um resultado em hello, onde, como se não tivéssemos definido as informações difusas, um resultado pode não ser encontrado. Mais informações podem ser encontradas na documentação.
O segundo estágio do pipeline adicionará os dados de destaque aos resultados antes de serem retornados ao cliente. Os metadados de destaque não fazem parte do documento original, daí a necessidade de adicioná-los usando o operador $meta antes da resposta. Você pode ler mais sobre o operador$meta e os metadados que ele pode exibir na documentação. Você também pode usar o operador$meta em um estágio$projectem vez de $addFields.
Como este é um pipeline de agregação do MongoDB, você pode combinar qualquer número de operadores de agregação, desde que $search seja o primeiro no pipeline.
Se houver dados na coleção, o aplicativo estará pronto para ser usado.

Projetando o front-end visualmente chamativo para os resultados do Atlas Search e o texto adjacente

O próximo passo é exibir os dados de pesquisa na tela. A maior parte do que vem a seguir diz respeito à massagem dos dados em um formato que queremos usar, o que inclui destacar visualmente os dados com marcação HTML.
Vamos precisar criar outro diretório de projeto, desta vez representando o front-end em vez do back-end. Dentro deste novo diretório, crie um arquivoindex.html com a seguinte marcação:
1<!DOCTYPE html>
2<html>
3 <head></head>
4 <body>
5 <div>
6 <input id="term" type="text" />
7 <button type="button" onclick="search()">Search</button>
8 </div>
9 <br />
10 <div id="output"></div>
11 <script>
12 const search = async () => {
13 let term = document.getElementById("term");
14 let output = document.getElementById("output");
15 };
16 </script>
17 </body>
18</html>
No código acima, temos um formulário que chama uma funçãosearch quando o botão é clicado. A partir de agora, a funçãosearch obtém somente o termo do Atlas Search e faz referência à área onde os resultados do Atlas Search devem ser produzidos.
Vamos restringir ainda mais o que a funçãosearch deve fazer.
1const search = async () => {
2 let term = document.getElementById("term");
3 let output = document.getElementById("output");
4 output.innerHTML = "";
5 let result = await fetch("http://localhost:3000/search?term=" + term.value)
6 .then(response => response.json());
7 result.forEach(chat => {
8 let messageContainer = document.createElement("div");
9 messageContainer.innerHTML = `<strong>Chat ${chat._id}</strong>`;
10 chat.messages.forEach(msg => {
11 let message = document.createElement("p");
12 chat.highlights.forEach(highlight => {
13 let texts = highlight.texts;
14 let replacements = texts.map(text => {
15 if(text.type == "hit") {
16 return "<mark>" + text.value + "</mark>";
17 } else {
18 return text.value;
19 }
20 }).join("");
21 let originals = texts.map(text => {
22 return text.value;
23 }).join("");
24 msg.message = msg.message.replace(originals, replacements);
25 });
26 message.innerHTML = msg.sender + ": " + msg.message;
27 messageContainer.appendChild(message);
28 });
29 output.appendChild(messageContainer);
30 });
31};
As modificações acima na função podem ser muito para incluir. Vamos detalhar o que está rolando.
Depois de limpar o espaço de saída, estamos fazendo uma solicitação para o back-end:
1let result = await fetch("http://localhost:3000/search?term=" + term.value)
2 .then(response => response.json());
Os resultados dessa solicitação terão os documentos encontrados, bem como os dados de destaque associados à pesquisa.
A próxima etapa será analisar cada um dos resultados e, em seguida, cada uma das mensagens dos resultados. É aqui que as coisas podem ficar um pouco confusas. O MongoDB retornará dados semelhantes aos seguintes quando se trata de destacar:
1{
2 "path": "messages.message",
3 "texts": [
4 {
5 "value": "This is another ",
6 "type": "text"
7 },
8 {
9 "value": "Hello",
10 "type": "hit"
11 },
12 {
13 "value": " world example",
14 "type": "text"
15 }
16 ],
17 "score": 0.7454098463058472
18},
Ele não faz exatamente o realce visual para nós. Em vez disso, ele nos dirá qual termo ou frase teve um sucesso em potencial e o texto adjacente. Com essas informações, precisamos destacar o acerto no JavaScript.
1let texts = highlight.texts;
2let replacements = texts.map(text => {
3 if(text.type == "hit") {
4 return "<mark>" + text.value + "</mark>";
5 } else {
6 return text.value;
7 }
8}).join("");
9let originals = texts.map(text => {
10 return text.value;
11}).join("");
Aqui, estamos construindo uma string a partir das peças de destaque originais, bem como uma string onde o acerto é envolto em marcação. O objetivo é usar a funçãoreplace no JavaScript, que exige um termo ou frase de pesquisa, bem como a substituição. Não podemos simplesmente substituir o resultado, porque e se nosso resultado fosse hello enquanto helloworld existia no chat sem espaços? A substituição do JavaScript não analisa as palavras de forma natural, portanto, a substituição automática de hello resultaria em helloworld sendo destacado incorretamente. É por isso que precisamos trabalhar com os dados adjacentes que o MongoDB retorna.
Depois de fazer a substituição do JavaScript pela string original e pela string modificada, podemos prepará-la para a saída com o seguinte:
1message.innerHTML = msg.sender + ": " + msg.message;
2messageContainer.appendChild(message);
Como mencionado anteriormente, o front-end está realmente fazendo muitas manipulações visuais usando os dados de resultado e destaque que o back-end criou.

Conclusão

Você acabou de ver como destacar visualmente os resultados de pesquisa na tela usando os dados de destaque retornados com o MongoDB Atlas Search. Embora destacar os resultados da pesquisa com marcação HTML e JavaScript não seja totalmente necessário, é uma ótima maneira de aprender sobre seus dados e como suas pesquisas estão operando.
Para saber mais sobre Atlas Search e criar um formulário de preenchimento automático, vale a pena conferir meu tutorial anterior sobre o tópico.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Consulta flexível com Atlas Search


Jul 12, 2024 | 3 min read
Tutorial

Guia de configuração do Atlas Stream Processing para usuários do Kafka Connector


Aug 23, 2024 | 15 min read
Tutorial

Primeiro passos na segurança do Atlas Stream Processing


May 17, 2024 | 9 min read
Tutorial

É seguro sair? Investigação de dados com o MongoDB


Sep 23, 2022 | 11 min read
Sumário