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

Armazenar dados binários com MongoDB e C++

Rishabh Bisht6 min read • Published Sep 18, 2023 • Updated Sep 18, 2023
C++Atlas
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Em aplicativos modernos, armazenar e recuperar arquivos binários de forma eficiente é um requisito crucial. O MongoDB permite isso com tipo de dados binários no BSON, que é um formato de serialização binária usado para armazenar documentos no MongoDB. Um valor binário BSON é uma array de bytes e tem um subtipo (como subtipo binário genérico, UUID, MD5 etc.) que indica como interpretar os dados binários. Consulte BSON types — MongoDB Manual para obter mais informações.
Neste tutorial, escreveremos um aplicativo de console em C++, usando o driver MongoDB C++ para carregar e baixar dados binários.
Observação:
  • Ao usar este método, lembre-se que o limite de tamanho do documento BSON no MongoDB é 16 MB. Se seus arquivos binários forem maiores que esse limite, considere usar o GridFS para um tratamento mais eficiente de arquivos grandes. Consulte o exemplo do GridFS em C++ para referência.
  • Os desenvolvedores costumam avaliar as vantagens e desvantagens ao armazenar dados binários no MongoDB. É essencial garantir que você também considerou diferentes estratégias para otimizar sua abordagem de gerenciamento de dados.

Pré-requisitos

  1. Conta do MongoDB Atlas com um cluster criado.
  2. Configuração IDE (como o Microsoft Visual Studio ou o Microsoft Visual Studio Code) com o driver MongoDB C e C++ instalado. Siga as instruções em Introdução ao MongoDB e C++ para instalar os drivers do MongoDB C/C++ e configurar o ambiente de desenvolvimento no Visual Studio. Instruções de instalação para outras plataformas estão disponíveis.
  3. Compilador com suporte a C++17 (para usar operaçõesstd::filesystem ).
  4. O endereço IP da sua máquina está na lista de permissões. Nota: Você pode adicionar 0.0.0.0/0 como o endereço IP, que deve permitir o acesso de qualquer máquina. Essa configuração não é recomendada para uso em produção.

Criando o aplicativo

Código fonte disponível aqui.
Como parte dos BSON types, o driver C++ fornece a estrutura b_binary que pode ser usada para armazenar valor de dados binários em um documento BSON. Consulte a API.
Começamos definindo a estrutura do nosso documento BSON. Definimos três chaves: name, pathe data. Eles contêm o nome do arquivo que está sendo carregado, seu caminho completo do disco e os dados reais do arquivo, respectivamente. Veja um documento de exemplo abaixo:
Documento de amostra com dados binários.
No código, eles são definidos com um #define para que seja fácil modificá-los a partir de um único local.

Funções auxiliares

Vamos adicionar uma função auxiliar, upload, que aceita um caminho de arquivo e uma coleção MongoDB como entradas. Seu objetivo principal é carregar o arquivo na coleção MongoDB especificada convertendo o arquivo em um valor binário BSON e construindo um documento BSON para representar os metadados e o conteúdo do arquivo. Aqui estão as principais etapas dentro da funçãoupload:
  1. Abra o arquivo no caminho fornecido e obtenha seu tamanho.
    1. O tamanho do arquivo é determinado movendo o ponteiro do arquivo para o final do arquivo e, em seguida, recuperando a posição atual, que corresponde ao tamanho do arquivo.
    2. O ponteiro do arquivo é então redefinido para o início do arquivo para ler o conteúdo posteriormente.
  2. Ler conteúdo do arquivo em um buffer: um buffer std::vector<char> é criado com um tamanho igual ao tamanho do arquivo para manter os dados binários do arquivo.
  3. Crie o valor binário BSON.
    1. Para representar o conteúdo do arquivo como valor binário BSON, o código cria um objetobsoncxx::types::b_binary .
    2. O objeto b_binary inclui o subtipo binário (definido como bsoncxx::binary_sub_type::k_binary), o tamanho do arquivo e os dados.
  4. Crie um documento BSON com três campos: name, pathe data.
  5. Inserir o documento na coleção.
1#include <mongocxx/client.hpp>
2#include <bsoncxx/builder/basic/document.hpp>
3#include <mongocxx/uri.hpp>
4#include <mongocxx/instance.hpp>
5
6#include <iostream>
7#include <fstream>
8#include <vector>
9#include <filesystem>
10
11#define FILE_NAME "name"
12#define FILE_PATH "path"
13#define FILE_DATA "data"
14
15using bsoncxx::builder::basic::kvp;
16using bsoncxx::builder::basic::make_document;
17
18// Upload a file to the collection.
19bool upload(const std::string& filePath, mongocxx::collection& collection)
20{
21 // Open the binary file
22 std::ifstream file(filePath, std::ios::binary | std::ios::ate);
23 if (!file)
24 {
25 std::cout << "Failed to open the file: " << filePath << std::endl;
26 return false;
27 }
28
29 // Get the file size.
30 std::streamsize fileSize = file.tellg();
31 file.seekg(0, std::ios::beg);
32
33 // Read the file content into a buffer
34 std::vector<char> buffer(fileSize);
35 if (!file.read(buffer.data(), fileSize))
36 {
37 std::cout << "Failed to read the file: " << filePath << std::endl;
38 return false;
39 }
40
41 // Create the binary object for bsoncxx.
42 bsoncxx::types::b_binary data{bsoncxx::binary_sub_type::k_binary, static_cast<std::uint32_t>(fileSize), reinterpret_cast<const std::uint8_t*>(buffer.data())};
43
44 // Create a document with the file name and file content.
45
46 auto doc = make_document(
47 kvp(FILE_NAME, std::filesystem::path(filePath).filename()),
48 kvp(FILE_PATH, filePath),
49 kvp(FILE_DATA, data));
50
51 // Insert the document into the collection.
52 collection.insert_one(doc.view());
53
54 std::cout << "Upload successful for: " << filePath << std::endl;
55 return true;
56}
Vamos escrever uma função auxiliar semelhante para executar o download. O código abaixo usa o nome do arquivo, a pasta de destino e uma coleção MongoDB como entradas. Esta função procura um arquivo por seu nome na coleção MongoDB especificada, extrai seus dados binários e os salva na pasta de destino especificada.
Aqui estão as principais etapas da funçãodownload:
  1. Crie uma consulta de filtro para encontrar o arquivo.
  2. Use a consulta para encontrar o documento na coleção.
  3. Extrair e salvar dados binários — os dados binários são acessados usando bsoncxx::document::view e, em seguida, recuperados do documento usando binaryDocView[FILE_DATA].get_binary().
  4. Crie um arquivo na pasta de destino e grave o conteúdo binário no arquivo.
1// Download a file from a collection to a given folder.
2bool download(const std::string& fileName, const std::string& destinationFolder, mongocxx::collection& collection)
3{
4 // Create a query to find the file by filename
5 auto filter = make_document(kvp(FILE_NAME, fileName));
6
7 // Find the document in the collection
8 auto result = collection.find_one(filter.view());
9
10 if (result)
11 {
12 // Get the binary data from the document
13 bsoncxx::document::view binaryDocView = result->view();
14 auto binaryData = binaryDocView[FILE_DATA].get_binary();
15
16 // Create a file to save the binary data
17 std::ofstream file(destinationFolder + fileName, std::ios::binary);
18 if (!file)
19 {
20 std::cout << "Failed to create the file: " << fileName << " at " << destinationFolder << std::endl;
21 return false;
22 }
23
24 // Write the binary data to the file
25 file.write(reinterpret_cast<const char*>(binaryData.bytes), binaryData.size);
26
27 std::cout << "Download successful for: " << fileName << " at " << destinationFolder << std::endl;
28 return true;
29 }
30 else
31 {
32 std::cout << "File not found in the collection: " << fileName << std::endl;
33 return false;
34 }
35}

A função main()

Com as funções auxiliares em vigor para realizar upload e download, vamos escrever a função principal que executará esse aplicativo. Aqui estão as principais etapas dentro da funçãomain:
  1. Conecte-se ao MongoDB: Estabeleça uma conexão com o MongoDB criando uma instância mongocxx::client.
  2. Obtenha o banco de dados (fileStorage) e a collection (files) para armazenar os arquivos.
  3. Carregar todos os arquivos encontrados na uploadFolder especificada: iterar recursivamente pela pasta usando std::filesystem::recursive_directory_iterator. Para cada arquivo encontrado, chame a função de upload para upload o arquivo na coleção MongoDB.
  4. Faça o download de arquivos específicos com nomes de arquivos conhecidos (fileName1 e fileName2) chamando a funçãodownload para recuperar e salvar os arquivos no downloadFolder.
  5. Da mesma forma, baixe todos os arquivos na coleção chamando find({}) para obter um cursor e iterar por cada documento na coleção, extraindo o nome do arquivo e, em seguida, chamando a funçãodownload para baixar e salvar o arquivo no downloadFolder.
    Observação: em uma situação do mundo real, a chamada find({}) deve ser feita com algum tipo de filtragem/paginação para evitar problemas com o consumo de memória e o desempenho.
Certifique-se de obter a string de conexão (URI), atualizá-la para mongoURIStr e definir o caminho e os nomes de arquivo diferentes para os que estão em seu disco.
1int main()
2{
3 try
4 {
5 auto mongoURIStr = "<Insert MongoDB Connection String>";
6 static const mongocxx::uri mongoURI = mongocxx::uri{ mongoURIStr };
7
8 // Create an instance.
9 mongocxx::instance inst{};
10
11 mongocxx::options::client client_options;
12 auto api = mongocxx::options::server_api{ mongocxx::options::server_api::version::k_version_1 };
13 client_options.server_api_opts(api);
14 mongocxx::client conn{ mongoURI, client_options};
15
16 const std::string dbName = "fileStorage";
17 const std::string collName = "files";
18
19 auto fileStorageDB = conn.database(dbName);
20 auto filesCollection = fileStorageDB.collection(collName);
21 // Drop previous data.
22 filesCollection.drop();
23
24 // Upload all files in the upload folder.
25 const std::string uploadFolder = "/Users/bishtr/repos/fileStorage/upload/";
26 for (const auto & filePath : std::filesystem::directory_iterator(uploadFolder))
27 {
28 if(std::filesystem::is_directory(filePath))
29 continue;
30
31 if(!upload(filePath.path().string(), filesCollection))
32 {
33 std::cout << "Upload failed for: " << filePath.path().string() << std::endl;
34 }
35 }
36
37 // Download files to the download folder.
38 const std::string downloadFolder = "/Users/bishtr/repos/fileStorage/download/";
39
40 // Search with specific filenames and download it.
41 const std::string fileName1 = "image-15.jpg", fileName2 = "Hi Seed Shaker 120bpm On Accents.wav";
42 for ( auto fileName : {fileName1, fileName2} )
43 {
44 if (!download(fileName, downloadFolder, filesCollection))
45 {
46 std::cout << "Download failed for: " << fileName << std::endl;
47 }
48 }
49
50 // Download all files in the collection.
51 auto cursor = filesCollection.find({});
52 for (auto&& doc : cursor)
53 {
54 auto fileName = std::string(doc[FILE_NAME].get_string().value);
55 if (!download(fileName, downloadFolder, filesCollection))
56 {
57 std::cout << "Download failed for: " << fileName << std::endl;
58 }
59 }
60 }
61 catch(const std::exception& e)
62 {
63 std::cout << "Exception encountered: " << e.what() << std::endl;
64 }
65
66 return 0;
67}

Aplicativo em ação

Antes de executar este aplicativo, adicione alguns arquivos (como imagens ou áudios) no diretóriouploadFolder .
Arquivos a serem carregados do disco local para o MongoDB.
Execute o aplicativo e você observará uma saída como esta, significando que os arquivos foram carregados e baixados com êxito.
Saída do aplicativo mostrando carregamentos e downloads bem-sucedidos.
Você pode ver a coleção no Atlas ou MongoDB Compass refletindo os arquivos carregados por meio do aplicativo.
Coleção com dados binários no MongoDB Compass.
Você observará os arquivos sendo baixados no diretóriodownloadFolderespecificado.
Arquivos baixados do MongoDB para o disco local.

Conclusão

Com este artigo, abordamos o armazenamento e a recuperação de dados binários de um MongoDB database, usando o MongoDB C++ driver. Os recursos robustos do MongoDB, combinados com a facilidade de uso fornecida pelo C++ driver, oferecem uma solução poderosa para lidar com o armazenamento de arquivos em aplicativos C++. Nós mal podemos esperar para ver o que você construirá a seguir! Compartilhe sua criação com a comunidade e conte para nós como ficou!

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

Atlas Search é uma virada de jogo!


Sep 09, 2024 | 2 min read
Tutorial

Amazon Web Services Amazon Web Services cole Visual ETL para seus dados no MongoDB Atlas


Nov 22, 2024 | 3 min read
Tutorial

Configuração MongoDB Data Federation


Jan 23, 2024 | 5 min read
Tutorial

Introdução ao Deno 2.0 e MongoDB


Oct 22, 2024 | 13 min read
Sumário
  • Pré-requisitos