MongoDB e C Sharp: tutorial de operações CRUD
Avalie esse Início rápido
Nesta publicação do Início rápido, mostrarei como configurar conexões entre C# e MongoDB. Em seguida, veremos as operações de criação, leitura, atualização e exclusão (CRUD) do banco de dados. Como você já sabe, C# é uma linguagem de uso geral e MongoDB é uma plataforma de dados de uso geral. Juntos, C# e MongoDB são uma combinação poderosa.
As ferramentas e versões que estou usando para esta série são:
C# é uma linguagem popular quando se usa o framework .NET. Se você pretende desenvolver no .NET e usar o MongoDB como sua camada de dados, o driver C# facilita isso.
Para acompanhar, usarei o Visual Studio 2019 no Windows 10 e me conectarei a um MongoDB Atlas cluster. Se você estiver usando um sistema operacional, IDE ou editor de texto diferente, o passo a passo pode ser ligeiramente diferente, mas o código em si deve ser bastante semelhante. Vamos dar uma olhada em como C# e MongoDB funcionam bem juntos.
Comece hoje mesmo com um cluster M0 no MongoDB Atlas. É gratuito para sempre e você poderá trabalhar junto com esta série de blogs.
Para esta demonstração, escolhi um aplicativo de console (.NET Core) e o nomeei
MongoDBConnectionDemo
. Em seguida, precisamos instalar o driver do MongoDB para C#/.NET para uma solução. Podemos fazer isso facilmente com o NuGet. Dentro do Visual Studio para Windows, acesse Tools -> NuGet Package Manager -> Manage NuGet Packages for Solution... Podemos procurar o MongoDB.Driver. Em seguida, clique em nosso projeto e selecione a versão do driver que desejamos. Neste caso, a versão estável mais recente é 2.9.1. Em seguida, clique em Install. Aceite os contratos de licença que aparecerem e vá para Program.cs
para começar.Para usar o
MongoDB.Driver
precisamos de acrescentar uma diretiva.1 using MongoDB.Driver;
Dentro do método
Main()
, estabeleceremos uma conexão com o MongoDB Atlas com uma string de conexão e, para testar a conexão, imprimiremos uma lista dos bancos de dados no servidor. O cluster do Atlas ao qual nos conectaremos tem o conjunto de dados de amostra do MongoDB Atlas instalado, portanto, poderemos ver uma boa lista de bancos de dados.A primeira etapa é passar a string de conexão do MongoDB Atlas para um objeto MongoClient e, em seguida, obter a lista de bancos de dados e imprimi-la.
1 MongoClient dbClient = new MongoClient(<<YOUR ATLAS CONNECTION STRING>>); 2 3 var dbList = dbClient.ListDatabases().ToList(); 4 5 Console.WriteLine("The list of databases on this server is: "); 6 foreach (var db in dbList) 7 { 8 Console.WriteLine(db); 9 }
Quando executamos o programa, obtemos o seguinte, mostrando a lista de bancos de dados:
1 The list of databases on this server is: 2 { "name" : "sample_airbnb", "sizeOnDisk" : 57466880.0, "empty" : false } 3 { "name" : "sample_geospatial", "sizeOnDisk" : 1384448.0, "empty" : false } 4 { "name" : "sample_mflix", "sizeOnDisk" : 45084672.0, "empty" : false } 5 { "name" : "sample_supplies", "sizeOnDisk" : 1347584.0, "empty" : false } 6 { "name" : "sample_training", "sizeOnDisk" : 73191424.0, "empty" : false } 7 { "name" : "sample_weatherdata", "sizeOnDisk" : 4427776.0, "empty" : false } 8 { "name" : "admin", "sizeOnDisk" : 245760.0, "empty" : false } 9 { "name" : "local", "sizeOnDisk" : 1919799296.0, "empty" : false }
Todo o programa até agora tem pouco mais de 20 linhas de código:
1 using System; 2 using MongoDB.Driver; 3 4 namespace test 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 MongoClient dbClient = new MongoClient(<<YOUR ATLAS CONNECTION STRING>>); 11 12 var dbList = dbClient.ListDatabases().ToList(); 13 14 Console.WriteLine("The list of databases on this server is: "); 15 foreach (var db in dbList) 16 { 17 Console.WriteLine(db); 18 } 19 } 20 } 21 }
Com uma conexão estabelecida, vamos em frente e começar a fazer operações CRUD dentro do banco de dados MongoDB Atlas. O primeiro passo é Criar alguns dados.
O MongoDB armazena dados em documentos JSON. Na verdade, eles são armazenados como objetos JSON binário (BSON) no disco, mas isso é assunto para outra publicação no blog. Em nosso conjunto de dados de amostra, há um
sample_training
com uma coleção grades
. Veja como ficaria um documento de amostra dessa coleção:1 { 2 "_id":{"$oid":"56d5f7eb604eb380b0d8d8ce"}, 3 "student_id":{"$numberDouble":"0"}, 4 "scores":[ 5 {"type":"exam","score":{"$numberDouble":"78.40446309504266"}}, 6 {"type":"quiz","score":{"$numberDouble":"73.36224783231339"}}, 7 {"type":"homework","score":{"$numberDouble":"46.980982486720535"}}, 8 {"type":"homework","score":{"$numberDouble":"76.67556138656222"}} 9 ], 10 "class_id":{"$numberDouble":"339"} 11 }
Há 10.000 alunos nesta coleção, 0-9,999. Vamos adicionar mais um usando C#. Para fazer isso, precisaremos usar outro pacote do NuGet,
MongoDB.Bson
. Começarei uma nova solução no Visual Studio e a chamarei de MongoDBCRUDExample
. Instalarei os pacotes MongoDB.Bson
e MongoDB.Driver
e usarei a string de conexão fornecida pelo MongoDB Atlas. Em seguida, acessarei nosso banco de dados e coleção específicos, sample_training
e grades
, respectivamente.1 using System; 2 using MongoDB.Bson; 3 using MongoDB.Driver; 4 5 namespace MongoDBCRUDExample 6 { 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 MongoClient dbClient = new MongoClient(<<YOUR ATLAS CONNECTION STRING>>); 12 13 var database = dbClient.GetDatabase("sample_training"); 14 var collection = database.GetCollection<BsonDocument>("grades"); 15 16 } 17 } 18 }
A variável
collection
é agora nosso principal ponto de referência para nossos dados. Como estamos usando um BsonDocument
ao atribuir nossa variável collection
, indiquei que não usarei um esquema predefinido. Isso utiliza o poder e a flexibilidade do document model do MongoDB. Eu poderia definir um objeto (plain-old-C#-object) para definir um esquema mais estritamente. Darei uma olhada nessa opção em um post futuro. Por enquanto, criarei um novo BsonDocument
para inserir no banco de dados.1 var document = new BsonDocument 2 { 3 { "student_id", 10000 }, 4 { "scores", new BsonArray 5 { 6 new BsonDocument{ {"type", "exam"}, {"score", 88.12334193287023 } }, 7 new BsonDocument{ {"type", "quiz"}, {"score", 74.92381029342834 } }, 8 new BsonDocument{ {"type", "homework"}, {"score", 89.97929384290324 } }, 9 new BsonDocument{ {"type", "homework"}, {"score", 82.12931030513218 } } 10 } 11 }, 12 { "class_id", 480} 13 };
Então, para criar o documento na coleção
sample_training.grades
, podemos fazer uma operação de inserção.1 collection.InsertOne(document);
Se você precisar fazer essa inserção de forma assíncrona, o driver C# do MongoDB é totalmente compatível com assíncrono. A mesma operação pode ser feita com:
1 await collection.InsertOneAsync(document);
Se você precisar inserir vários documentos ao mesmo tempo, o MongoDB também ajuda com os métodos
InsertMany
ou InsertManyAsync
.Vimos como estruturar um documento BSON em C# e, em seguida, Criar esse documento dentro de um MongoDB database. O driver C# do MongoDB facilita o uso dos métodos
InsertOne()
, InsertOneAsync()
, InsertMany()
ou InsertManyAsync()
. Agora que Criamos os dados, queremos Ler os dados.Para ler documento no MongoDB, usamos o método Find(). Esse método nos permite encadear uma variedade de métodos a ele, alguns dos quais veremos nesta publicação. Para obter o primeiro documento da coleção, podemos usar o método
FirstOrDefault
ou FirstOrDefaultAsync
e imprimir o resultado no console.1 var firstDocument = collection.Find(new BsonDocument()).FirstOrDefault(); 2 Console.WriteLine(firstDocument.ToString());
retorna...
1 { "_id" : ObjectId("56d5f7eb604eb380b0d8d8ce"), 2 "student_id" : 0.0, 3 "scores" : [ 4 { "type" : "exam", "score" : 78.404463095042658 }, 5 { "type" : "quiz", "score" : 73.362247832313386 }, 6 { "type" : "homework", "score" : 46.980982486720535 }, 7 { "type" : "homework", "score" : 76.675561386562222 } 8 ], 9 "class_id" : 339.0 }
Você pode se perguntar por que não estamos usando
Single
, já que ele também retorna um documento. Bem, isso também precisa garantir que o documento retornado seja o único documento desse tipo na coleção, o que significa examinar toda a coleção.Vamos localizar o documento que criamos e imprimi-lo no console. A primeira etapa é criar um filtro para executar uma query no nosso documento específico.
1 var filter = Builders<BsonDocument>.Filter.Eq("student_id", 10000);
Aqui estamos definindo um filtro para procurar um documento onde o
student_id
é igual a 10000
. Podemos passar o filtro para o método Find()
para obter o primeiro documento que corresponda à query.1 var studentDocument = collection.Find(filter).FirstOrDefault(); 2 Console.WriteLine(studentDocument.ToString());
retorna...
1 { "_id" : ObjectId("5d88f88cec6103751b8a0d7f"), 2 "student_id" : 10000, 3 "scores" : [ 4 { "type" : "exam", "score" : 88.123341932870233 }, 5 { "type" : "quiz", "score" : 74.923810293428346 }, 6 { "type" : "homework", "score" : 89.979293842903246 }, 7 { "type" : "homework", "score" : 82.129310305132179 } 8 ], 9 "class_id" : 480 }
Se não for encontrado um documento que corresponda à query, o método
Find()
retornará nulo. Encontrar o primeiro documento em uma coleção ou com uma query é uma tarefa frequente. No entanto, o que dizer de situações em que todos os documentos precisam ser retornados, seja em uma coleção ou a partir de uma query?Para situações em que o conjunto de resultados esperado é pequeno, os métodos
ToList()
ou ToListAsync()
podem ser usados para recuperar todos os documento de uma query ou de uma coleção.1 var documents = collection.Find(new BsonDocument()).ToList();
Os filtros também podem ser passados aqui, por exemplo, para obter documentos com pontuações de exames iguais ou superiores a 95. O filtro aqui parece um pouco mais complicado, mas, graças à sintaxe do driver do MongoDB, é relativamente fácil de seguir. Estamos filtrando os documentos nos quais, dentro do array
scores
, há um subdocumento exam
com um valor score
maior ou igual a 95.1 var highExamScoreFilter = Builders<BsonDocument>.Filter.ElemMatch<BsonValue>( 2 "scores", new BsonDocument { { "type", "exam" }, 3 { "score", new BsonDocument { { "$gte", 95 } } } 4 }); 5 var highExamScores = collection.Find(highExamScoreFilter).ToList();
Para situações em que é necessário repetir os documentos que são retornados, também há algumas maneiras de fazer isso. Em uma situação síncrona, uma declaração C#
foreach
pode ser usada com o método adaptador ToEnumerable
. Nessa situação, em vez de usar o método ToList()
, usaremos o método ToCursor()
.1 var cursor = collection.Find(highExamScoreFilter).ToCursor(); 2 foreach (var document in cursor.ToEnumerable()) 3 { 4 Console.WriteLine(document); 5 }
Isso pode ser realizado de forma assíncrona com o método
ForEachAsync
também:1 await collection.Find(highExamScoreFilter).ForEachAsync(document => Console.WriteLine(document));
Com o retorno de muitos documentos no conjunto de resultados, geralmente é útil classificar os resultados. Podemos usar o método Sort() para fazer isso e ver qual aluno teve a maior pontuação no exame.
1 var sort = Builders<BsonDocument>.Sort.Descending("student_id"); 2 3 var highestScores = collection.Find(highExamScoreFilter).Sort(sort);
E podemos anexar o método
First()
a isso para obter apenas o melhor aluno.1 var highestScore = collection.Find(highExamScoreFilter).Sort(sort).First(); 2 3 Console.WriteLine(highestScore);
Com base no conjunto de dados de amostra do Atlas, o documento com
student_id
de 9997 deve ser retornado com uma pontuação de exame de 95.441609472871946.O driver C# para MongoDB oferece muitas maneiras de ler dados do banco de dados e suporta métodos síncronos e assíncronos para consultar os dados. Ao passar um filtro para o método
Find()
, podemos executar queries de registros específicos. A sintaxe para criar filtros e consultar o banco de dados é direta e fácil de ler, tornando essa etapa das operações CRUD em C# e MongoDB simples de usar.Com os dados criados e podendo ser lidos, vamos dar uma olhada em como podemos executar operações de atualização.
Até agora, neste Início Rápido de C# para CRUD do MongoDB, exploramos como criar e ler dados em um MongoDB database usando C#. Vimos como adicionar filtros à nossa query e como classificar os dados. Esta seção é sobre a operação atualizar e como o C# e o MongoDB trabalham juntos para realizar essa importante tarefa.
Lembre-se de que estamos trabalhando com esta versão
BsonDocument
de um registro de aluno:1 var document = new BsonDocument 2 { 3 { "student_id", 10000 }, 4 { "scores", new BsonArray 5 { 6 new BsonDocument{ {"type", "exam"}, {"score", 88.12334193287023 } }, 7 new BsonDocument{ {"type", "quiz"}, {"score", 74.92381029342834 } }, 8 new BsonDocument{ {"type", "homework"}, {"score", 89.97929384290324 } }, 9 new BsonDocument{ {"type", "homework"}, {"score", 82.12931030513218 } } 10 } 11 }, 12 { "class_id", 480} 13 };
Após o início do semestre letivo, o instrutor do nosso aluno do exemplo percebe que ele está frequentando a turma errada. Devido a esse erro, a administração da escola precisa alterar ou atualizar o
class_id
associado ao seu registo. Ele irá para a turma 483.Para atualizar um documento, precisamos que dois bits passem para um comando
Update
. Precisamos de um filtro para determinar quais documentos serão atualizados. Em segundo lugar, precisamos do que estamos tentando atualizar.Para nosso exemplo, queremos filtrar com base no documento com
student_id
igual a 10000.1 var filter = Builders<BsonDocument>.Filter.Eq("student_id", 10000)
Em seguida, queremos fazer a alteração no
class_id
. Podemos fazer isso com Set()
no método Update()
.1 var update = Builders<BsonDocument>.Update.Set("class_id", 483);
Em seguida, usamos o método
UpdateOne()
para fazer as alterações. Observe aqui que o MongoDB atualizará no máximo um documento usando o método UpdateOne()
. Se nenhum documento corresponder ao filtro, nenhum documento será atualizado.1 collection.UpdateOne(filter, update);
Nem todas as alterações são tão simples quanto alterar um único campo. Vamos usar um filtro diferente, que selecione um documento com um tipo de pontuação específico para os testes:
1 var arrayFilter = Builders<BsonDocument>.Filter.Eq("student_id", 10000) & Builders<BsonDocument> 2 .Filter.Eq("scores.type", "quiz");
Agora, se quisermos fazer a mudança na pontuação do quiz, podemos fazer isso com
Set()
também, mas identificar qual elemento específico deve ser alterado é um pouco diferente. Podemos usar o operador $ posicional para acessar o quiz score
no array. O operador $ por conta própria diz "alterar o elemento de array que combinamos dentro da query" - o filtro corresponde com scores.type
igual a quiz
e esse é o elemento que será atualizado com o conjunto.1 var arrayUpdate = Builders<BsonDocument>.Update.Set("scores.$.score", 84.92381029342834);
E, novamente, usamos o método
UpdateOne()
para fazer as alterações.1 collection.UpdateOne(arrayFilter , arrayUpdate);
Se você vem lendo esta série de blogs, mencionei que o driver C# oferece suporte a interações sincronizadas e assíncronas com o MongoDB. Fazer atualizações de dados não é diferente. Há também um método
UpdateOneAsync()
disponível. Além disso, para os casos em que vários documentos precisam ser atualizados de uma só vez, existem as opções UpdateMany()
ou UpdateManyAsync()
. Os métodos UpdateMany()
e UpdateManyAsync()
correspondem aos documentos no Filter
e atualizam todos os documentos que correspondem aos requisitos do filtro.Update
é um operador importante no mundo CRUD. Não ser capaz de atualizar as coisas à medida que elas mudam tornaria a programação incrivelmente difícil. Felizmente, o C# e o MongoDB continuam a trabalhar bem juntos para tornar as operações possíveis e fáceis de usar. Seja atualizando a nota de um aluno ou atualizando o endereço de um usuário, Atualizar está aqui para lidar com as alterações. O código para as operações criar, ler e atualizar pode ser encontrado neste gist.Estamos encerrando esta série de operações CRUD do Início Rápido do MongoDB C# com apenas uma operação restante para explorar, Excluir.
Lembre-se de que você pode começar a usar um cluster M0 no MongoDB Atlas hoje mesmo. É gratuito para sempre e você poderá trabalhar junto com esta série de blogs.
Para continuar a história do aluno, vejamos o que aconteceria se o aluno abandonasse o curso e tivesse que ter suas notas excluídas. Mais uma vez, o driver do MongoDB para C# simplifica esse processo. Além disso, ele oferece opções síncronas e assíncronas para as operações.
A primeira etapa do processo de exclusão é criar um filtro para o(s) documento(s) que precisa(m) ser excluído(s). No exemplo desta série, usei um documento com um valor
student_id
de 10000
para trabalhar. Como excluirei apenas esse único registro, usarei o método DeleteOne()
(para situações assíncronas, o método DeleteOneAsync()
está disponível). Porém, quando um filtro corresponde a mais de um documento e todos eles precisam ser excluídos, o método DeleteMany()
ou DeleteManyAsync
pode ser usado.Este é o registro que quero excluir.
1 { 2 { "student_id", 10000 }, 3 { "scores", new BsonArray 4 { 5 new BsonDocument{ {"type", "exam"}, {"score", 88.12334193287023 } }, 6 new BsonDocument{ {"type", "quiz"}, {"score", 84.92381029342834 } }, 7 new BsonDocument{ {"type", "homework"}, {"score", 89.97929384290324 } }, 8 new BsonDocument{ {"type", "homework"}, {"score", 82.12931030513218 } } 9 } 10 }, 11 { "class_id", 483} 12 };
Definirei o filtro para corresponder
student_id
ao documento igual a 10000
:1 var deleteFilter = Builders<BsonDocument>.Filter.Eq("student_id", 10000);
Supondo que temos uma variável
collection
atribuída para a coleção grades
, em seguida, passamos o filtro para o método DeleteOne()
.1 collection.DeleteOne(deleteFilter);
Se este comando for executado na coleção
grades
, o documento com student_id
igual a 10000
desaparecerá. Observe aqui que DeleteOne()
exclui o primeiro documento da coleção que corresponda ao filtro. Em nosso conjunto de dados de exemplo, como há apenas um único aluno com student_id
igual a 10000
, obtemos os resultados desejados.Para fins de argumentação, vamos imaginar que as regras da instituição de ensino sejam incrivelmente rígidas. Se você obtiver uma pontuação inferior a 60 no primeiro exame, será automaticamente eliminado do curso. Poderíamos usar um
for
loop com DeleteOne()
para percorrer toda a coleção, encontrar um único documento que corresponda a uma pontuação de exame inferior a 60, excluí-lo e repetir. Lembre-se de que DeleteOne()
exclui apenas o primeiro documento encontrado que corresponda ao filtro. Embora isso possa funcionar, não é muito eficiente, pois são feitas várias chamadas ao banco de dados. Então, como lidamos com situações que exigem a exclusão de vários registros? Podemos usar DeleteMany()
.Vamos definir um novo filtro para que a pontuação do exame seja menor que 60:
1 var deleteLowExamFilter = Builders<BsonDocument>.Filter.ElemMatch<BsonValue>("scores", 2 new BsonDocument { { "type", "exam" }, {"score", new BsonDocument { { "$lt", 60 }}} 3 });
Com o filtro definido, nós o passamos para o método
DeleteMany()
:1 collection.DeleteMany(deleteLowExamFilter);
Com esse comando sendo executado, todos os documento de registro de alunos com notas baixas no exame seriam excluídos da coleção.
Esta série de início rápido C# cobriu as várias operações CRUD (Criar, Ler, Atualizar e Excluir) no MongoDB usando documentos BSON básicos. Vimos como usar filtros para corresponder a documentos específicos que queremos ler, atualizar ou excluir. Esta série foi, até agora, uma introdução suave a C Sharp e MongoDB.
No entanto, os documentos BSON não são a única maneira de usar o MongoDB com C-Sharp. Em nossos aplicativos, geralmente temos classes definindo objetos. Podemos mapear nossas classes para Documentos BSON para trabalhar com dados como faríamos no código. Veremos o mapeamento em uma outra publicação.