Primeiros passos no MongoDB e C++
Avalie esse Tutorial
Ferramentas e bibliotecas usadas neste tutorial:
- Microsoft Windows 11
- Microsoft Visual Studio 2022 17.3.6
- Padrão de linguagem: C++17
- Versão do driver C do MongoDB: 1.23
- Versão do driver C++ do MongoDB: 3.7.0
- boost: 1.80.0
- Python: 3.10
- CMake: 3.25.0
- Conta do MongoDB Atlas com um cluster criado.
- O endereço IP da sua máquina está na lista de permissões. Nota: Você pode adicionar 0000/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.
Etapa 1: instale o Visual Studio: Baixe as ferramentas do Visual Studio - Instale gratuitamente para Windows, Mac, Linux.
Na aba Volumes de trabalho, durante a instalação, selecione "Desktop development with C++. "
Etapa 2: instale o CMake: baixar | CMake
- Para simplificar, escolha o instalador.
- Na configuração, certifique-se de selecionar "Add CMake to the system PATH for all users." Isso permite que o executável CMake seja facilmente acessível.
Etapa 4: (opcional) baixe a biblioteca boost em Transferências Boost e faça a extração para C:\boost.
Instruções e configurações detalhadas disponíveis aqui:
O driver C++ tem uma dependência no driver C. Portanto, precisamos instalar o driver C primeiro.
- Baixe o driver C
- Baixe o tarball de lançamento — Versões · mongodb/mongo-c-driver — e faça a extração para C:\Repos\mongo-c-driver-1.23.0.
- Criação de configuração via CMake
- Inicie o powershell/terminal como administrador.
- Navegue até C:\Repos\mongo-c-driver-1.23.0 e crie uma nova pasta denominada cmake-build para os arquivos de compilação.
- Navegue até C:\Repos\mongo-c-driver-1.23.0\cmake-build.
- Execute o comando abaixo para configurar e gerar arquivos de criação usando o CMake.
1 cmake -G "Visual Studio 17 2022" -A x64 -S "C:\Repos\mongo-c-driver-1.23.0" -B "C:\Repos\mongo-c-driver-1.23.0\cmake-build"
Observação: a configuração da criação também pode ser feita com o aplicativo CMake GUI.
- Executar criação
- O tipo de construção padrão do Visual Studio é Depuração. Uma criação de versão com informações de depuração é recomendada para uso na produção.
- Execute o comando abaixo para criar e instalar o driver
1 cmake --build . --config RelWithDebInfo --target install
- Agora você deve ver libmongoc e libbson instalados em C:/Program Files/mongo-c-driver.
- Mova o mongo-c-driver para C:/ por conveniência. Portanto, o Driver C agora deve estar presente em C:/mongo-c-driver.
- Baixe o driver C++
- Baixe o tarball de lançamento — Versões · mongodb/mongo-cxx-driver — e extraia-o para C:\Repos\mongo-cxx-driver-r3.7.0.
- Configurar a criação via CMake
- Inicie o powershell/terminal como administrador.
- Navegue até C:\Repos\mongo-cxx-driver-r3.7.0\build.
- Execute o comando abaixo para gerar e configurar arquivos de construção via CMake.
1 cmake .. -G "Visual Studio 17 2022" -A x64 -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_FLAGS="/Zc:__cplusplus /EHsc" -DCMAKE_PREFIX_PATH=C:\mongo-c-driver -DCMAKE_INSTALL_PREFIX=C:\mongo-cxx-driver
Observação: a configuração DCMAKE_CXX_FLAGS não deve ser solicitada para a versão 3.7.1 e superiores do driver C++.
- Executar criação
- Execute o comando abaixo para criar e instalar o driver
1 cmake --build . --config RelWithDebInfo --target install
- Agora você deve ver o driver C++ instalado em C:\mongo-cxx-driver.
- Crie um novo projeto no Visual Studio.
- Selecione Console App nos modelos.
- O Visual Studio deve criar um novo projeto e abrir um arquivo .cpp que imprime "Hello World." Navegue até o painel Solution Explorer, clique com o botão direito do mouse no nome da solução (MongoCXXGettingStarted, neste caso) e clique em Propriedades.
- Vá para Configuration Properties (Propriedades de configuração) > C/C++ > General (Geral)> Additional Include Directories (Diretórios de inclusão adicionais) e adicione os diretórios de inclusão das pastas de instalação do driver C e C++, conforme mostrado abaixo.
- Vá para Configuração de propriedades > C/C++ > Linguagem e altere o padrão de linguagem C++ para C++17.
- Vá para Propriedades de configuração > C/C++ > Linha de comando e adicione /Zc:__cplusplus no campo Opções adicionais. Esse sinalizador é necessário para optar pela definição correta de __cplusplus.
- Vá para Configuration Properties (Propriedades de configuração) > Linker (Vinculador) > Input (Entrada) e adicione as bibliotecas do driver na seção Additional Dependencies (Dependências adicionais), conforme mostrado abaixo.
- Vá para Configuration Properties (Propriedades de configuração) > Debugging (Depuração) > Environment (Ambiente) para adicionar um caminho aos executáveis do driver, conforme mostrado abaixo.
Fonte disponível aqui
Vamos criar um aplicativo que mantenha os registros dos alunos. Vamos inserir os dados dos alunos do usuário, os salvaremos no banco de dados e executaremos diferentes operações CRUD lá.
Vamos começar com um programa simples para se conectar ao MongoDB Atlas cluster e acessar os bancos de dados. Obtenha a string (URI) para o cluster e crie uma nova variável de ambiente com a chave como "MONGODB_URI" e o valor como a string (URI). É uma boa prática manter a string desacoplada do código.
Dica: reinicie seu computador depois de criar a variável de ambiente, caso a função"getEnvironmentVariable" não consiga recuperar a variável de ambiente.
1 #include <mongocxx/client.hpp> 2 #include <bsoncxx/builder/stream/document.hpp> 3 #include <bsoncxx/json.hpp> 4 #include <mongocxx/uri.hpp> 5 #include <mongocxx/instance.hpp> 6 #include <algorithm> 7 #include <iostream> 8 #include <vector> 9 using namespace std; 10 std::string getEnvironmentVariable(std::string environmentVarKey) 11 { 12 char* pBuffer = nullptr; 13 size_t size = 0; 14 auto key = environmentVarKey.c_str(); 15 // Use the secure version of getenv, ie. _dupenv_s to fetch environment variable. 16 if (_dupenv_s(&pBuffer, &size, key) == 0 && pBuffer != nullptr) 17 { 18 std::string environmentVarValue(pBuffer); 19 free(pBuffer); 20 return environmentVarValue; 21 } 22 else 23 { 24 return ""; 25 } 26 } 27 auto mongoURIStr = getEnvironmentVariable("MONGODB_URI"); 28 static const mongocxx::uri mongoURI = mongocxx::uri{ mongoURIStr }; 29 // Get all the databases from a given client. 30 vector<string> getDatabases(mongocxx::client& client) 31 { 32 return client.list_database_names(); 33 } 34 int main() 35 { 36 // Create an instance. 37 mongocxx::instance inst{}; 38 mongocxx::options::client client_options; 39 auto api = mongocxx::options::server_api{ mongocxx::options::server_api::version::k_version_1 }; 40 client_options.server_api_opts(api); 41 mongocxx::client conn{ mongoURI, client_options} 42 auto dbs = getDatabases(conn); 43 for (auto db : dbs) 44 { 45 cout << db << endl; 46 } 47 return 0; 48 }
Clique em "Launch Debugger" para iniciar o aplicativo de console. A saída deve ser semelhante a esta:
Como o banco de dados foi conectado com sucesso ao nosso aplicativo, vamos escrever algumas funções auxiliares para interagir com o banco de dados, realizando operações CRUD.
1 // Create a new collection in the given database. 2 void createCollection(mongocxx::database& db, const string& collectionName) 3 { 4 db.create_collection(collectionName); 5 } 6 // Create a document from the given key-value pairs. 7 bsoncxx::document::value createDocument(const vector<pair<string, string>>& keyValues) 8 { 9 bsoncxx::builder::stream::document document{}; 10 for (auto& keyValue : keyValues) 11 { 12 document << keyValue.first << keyValue.second; 13 } 14 return document << bsoncxx::builder::stream::finalize; 15 } 16 // Insert a document into the given collection. 17 void insertDocument(mongocxx::collection& collection, const bsoncxx::document::value& document) 18 { 19 collection.insert_one(document.view()); 20 }
1 // Print the contents of the given collection. 2 void printCollection(mongocxx::collection& collection) 3 { 4 // Check if collection is empty. 5 if (collection.count_documents({}) == 0) 6 { 7 cout << "Collection is empty." << endl; 8 return; 9 } 10 auto cursor = collection.find({}); 11 for (auto&& doc : cursor) 12 { 13 cout << bsoncxx::to_json(doc) << endl; 14 } 15 } 16 // Find the document with given key-value pair. 17 void findDocument(mongocxx::collection& collection, const string& key, const string& value) 18 { 19 // Create the query filter 20 auto filter = bsoncxx::builder::stream::document{} << key << value << bsoncxx::builder::stream::finalize; 21 //Add query filter argument in find 22 auto cursor = collection.find({ filter }); 23 for (auto&& doc : cursor) 24 { 25 cout << bsoncxx::to_json(doc) << endl; 26 } 27 }
1 // Update the document with given key-value pair. 2 void updateDocument(mongocxx::collection& collection, const string& key, const string& value, const string& newKey, const string& newValue) 3 { 4 collection.update_one(bsoncxx::builder::stream::document{} << key << value << bsoncxx::builder::stream::finalize, 5 bsoncxx::builder::stream::document{} << "$set" << bsoncxx::builder::stream::open_document << newKey << newValue << bsoncxx::builder::stream::close_document << bsoncxx::builder::stream::finalize); 6 }
1 // Delete a document from a given collection. 2 void deleteDocument(mongocxx::collection& collection, const bsoncxx::document::value& document) 3 { 4 collection.delete_one(document.view()); 5 }
Com todas as funções auxiliares implantadas, vamos criar um menu na função principal que podemos usar para interagir com o aplicativo.
1 // ********************************************** I/O Methods ********************************************** 2 // Input student record. 3 void inputStudentRecord(mongocxx::collection& collection) 4 { 5 string name, rollNo, branch, year; 6 cout << "Enter name: "; 7 cin >> name; 8 cout << "Enter roll number: "; 9 cin >> rollNo; 10 cout << "Enter branch: "; 11 cin >> branch; 12 cout << "Enter year: "; 13 cin >> year; 14 insertDocument(collection, createDocument({ {"name", name}, {"rollNo", rollNo}, {"branch", branch}, {"year", year} })); 15 } 16 // Update student record. 17 void updateStudentRecord(mongocxx::collection& collection) 18 { 19 string rollNo, newBranch, newYear; 20 cout << "Enter roll number: "; 21 cin >> rollNo; 22 cout << "Enter new branch: "; 23 cin >> newBranch; 24 cout << "Enter new year: "; 25 cin >> newYear; 26 updateDocument(collection, "rollNo", rollNo, "branch", newBranch); 27 updateDocument(collection, "rollNo", rollNo, "year", newYear); 28 } 29 // Find student record. 30 void findStudentRecord(mongocxx::collection& collection) 31 { 32 string rollNo; 33 cout << "Enter roll number: "; 34 cin >> rollNo; 35 findDocument(collection, "rollNo", rollNo); 36 } 37 // Delete student record. 38 void deleteStudentRecord(mongocxx::collection& collection) 39 { 40 string rollNo; 41 cout << "Enter roll number: "; 42 cin >> rollNo; 43 deleteDocument(collection, createDocument({ {"rollNo", rollNo} })); 44 } 45 // Print student records. 46 void printStudentRecords(mongocxx::collection& collection) 47 { 48 printCollection(collection); 49 } 50 // ********************************************** Main ********************************************** 51 int main() 52 { 53 if(mongoURI.to_string().empty()) 54 { 55 cout << "URI is empty"; 56 return 0; 57 } 58 // Create an instance. 59 mongocxx::instance inst{}; 60 mongocxx::options::client client_options; 61 auto api = mongocxx::options::server_api{ mongocxx::options::server_api::version::k_version_1 }; 62 client_options.server_api_opts(api); 63 mongocxx::client conn{ mongoURI, client_options}; 64 const string dbName = "StudentRecords"; 65 const string collName = "StudentCollection"; 66 auto dbs = getDatabases(conn); 67 // Check if database already exists. 68 if (!(std::find(dbs.begin(), dbs.end(), dbName) != dbs.end())) 69 { 70 // Create a new database & collection for students. 71 conn[dbName]; 72 } 73 auto studentDB = conn.database(dbName); 74 auto allCollections = studentDB.list_collection_names(); 75 // Check if collection already exists. 76 if (!(std::find(allCollections.begin(), allCollections.end(), collName) != allCollections.end())) 77 { 78 createCollection(studentDB, collName); 79 } 80 auto studentCollection = studentDB.collection(collName); 81 // Create a menu for user interaction 82 int choice = -1; 83 do while (choice != 0) 84 { 85 //system("cls"); 86 cout << endl << "**************************************************************************************************************" << endl; 87 cout << "Enter 1 to input student record" << endl; 88 cout << "Enter 2 to update student record" << endl; 89 cout << "Enter 3 to find student record" << endl; 90 cout << "Enter 4 to delete student record" << endl; 91 cout << "Enter 5 to print all student records" << endl; 92 cout << "Enter 0 to exit" << endl; 93 cout << "Enter Choice : "; 94 cin >> choice; 95 cout << endl; 96 switch (choice) 97 { 98 case 1: 99 inputStudentRecord(studentCollection); 100 break; 101 case 2: 102 updateStudentRecord(studentCollection); 103 break; 104 case 3: 105 findStudentRecord(studentCollection); 106 break; 107 case 4: 108 deleteStudentRecord(studentCollection); 109 break; 110 case 5: 111 printStudentRecords(studentCollection); 112 break; 113 case 0: 114 break; 115 default: 116 cout << "Invalid choice" << endl; 117 break; 118 } 119 } while (choice != 0); 120 return 0; 121 }
Quando esse aplicativo é executado, é possível gerenciar os registros dos alunos por meio da interface do console. Aqui está uma demonstração:
Você também pode ver a coleção no Atlas refletindo qualquer alteração feita por meio do aplicativo de console.
Com este artigo, abordamos a instalação do driver C/C++ e a criação de um aplicativo de console no Visual Studio que se conecta ao MongoDB Atlas para executar operações CRUD básicas.