Introdução ao MongoDB e ao Java - Tutorial de operações CRUD
Avalie esse Início rápido
- Atualizar para o Java 21
- Atualize o driver Java para 5.0.0
- Atualize
logback-classic
para 1.2.13 - Atualize o método
preFlightChecks
para oferecer suporte a clusters compartilhados e dedicados do MongoDB Atlas.
- Atualizar para o Java 17
- Atualize o driver Java para 4.11.1
- Atualize o mongodb-crypt para 1.8.0
- Atualize o driver Java para 4.2.2.
- Exemplo de criptografia no nível do campo do lado do cliente adicionado.
- Atualize o driver Java para 4.1.1.
- O registro do driver Java do MongoDB agora está ativado por meio da popular APISLF4J, então adicionei logback no
pom.xml
e um arquivo de configuraçãologback.xml
.
Nesta primeira publicação no blog da série Java Quick Start, mostrarei como configurar seu projeto Java com o Maven e executar um comando MongoDB em Java. Em seguida, exploraremos as operações mais comuns — como criar, ler, atualizar e excluir — usando o driver Java do MongoDB. Também mostrarei algumas das opções e recursos mais poderosos disponíveis como parte do driver Java do MongoDB para cada uma dessas operações, dando-lhe uma base grande de conhecimento para desenvolver ao longo da série.
Em futuras publicações no blog, vamos seguir em frente e trabalhar com:
- Driver de fluxos reativos do MongoDB Java
O Java é a linguagem mais popular no setor de informática na data desta publicação no blog, e os desenvolvedores votaram no MongoDB como o banco de dados mais desejado por quatro anos consecutivos. Nesta série de publicações no blog, demonstrarei como essas duas grandes tecnologias são poderosas quando combinadas e como você pode acessar esse poder.
Para acompanhar, você pode usar qualquer ambiente de sua preferência e o ambiente de desenvolvimento integrado de sua escolha. Usarei o Maven 3.8.7 e o Java OpenJDK 21, mas é muito fácil atualizar o código para oferecer suporte a versões mais antigas do Java, portanto, fique à vontade para usar o JDK de sua escolha e atualizar a versão do Java adequadamente no arquivo pom.xml em que estamos prestes a configurar.
Para o cluster do MongoDB, usaremos um cluster do MongoDB de camada grátis M0 do MongoDB Atlas. Se você ainda não tiver um, confira minha publicação no blog Iniciar com um cluster M0.
Obtenha seu cluster M0 gratuito no MongoDB Atlas hoje mesmo. Ele é gratuito para sempre e você poderá usá-lo para trabalhar com os exemplos desta série de blogs.
Vamos dar uma olhada em como Java e MongoDB funcionam juntos.
Para começar, precisaremos configurar um novo projeto Maven. Você tem duas opções neste momento. Pode clonar o repositório git desta série ou criar e configurar o projeto Maven.
Se você optar por usar o git, obterá todo o código imediatamente. Ainda assim, recomendo que você leia o manual de configuração.
Você pode clonar o repositório, se quiser, com o comando a seguir.
1 git clone git@github.com:mongodb-developer/java-quick-start.git
Você pode usar seu IDE favorito para criar um novo projeto Maven para você ou pode criar o projeto Maven manualmente. De qualquer forma, você deve obter a seguinte arquitetura de pasta:
1 java-quick-start/ 2 ├── pom.xml 3 └── src 4 └── main 5 └── java 6 └── com 7 └── mongodb 8 └── quickstart
O arquivo pom.xml deve conter o seguinte código:
1 2 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://maven.apache.org/POM/4.0.0" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>com.mongodb</groupId> 8 <artifactId>java-quick-start</artifactId> 9 <version>1.0-SNAPSHOT</version> 10 11 <properties> 12 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 13 <maven-compiler-plugin.source>21</maven-compiler-plugin.source> 14 <maven-compiler-plugin.target>21</maven-compiler-plugin.target> 15 <maven-compiler-plugin.version>3.12.1</maven-compiler-plugin.version> 16 <mongodb-driver-sync.version>5.0.0</mongodb-driver-sync.version> 17 <mongodb-crypt.version>1.8.0</mongodb-crypt.version> 18 <!-- Keeping 1.2.13 until mongodb-crypt makes slf4j-api an optional dependency --> 19 <!-- https://jira.mongodb.org/browse/MONGOCRYPT-602 --> 20 <logback-classic.version>1.2.13</logback-classic.version> 21 <exec-maven-plugin.version>3.1.1</exec-maven-plugin.version> 22 </properties> 23 24 <dependencies> 25 <dependency> 26 <groupId>org.mongodb</groupId> 27 <artifactId>mongodb-driver-sync</artifactId> 28 <version>${mongodb-driver-sync.version}</version> 29 </dependency> 30 <dependency> 31 <groupId>org.mongodb</groupId> 32 <artifactId>mongodb-crypt</artifactId> 33 <version>${mongodb-crypt.version}</version> 34 </dependency> 35 <dependency> 36 <groupId>ch.qos.logback</groupId> 37 <artifactId>logback-classic</artifactId> 38 <version>${logback-classic.version}</version> 39 </dependency> 40 </dependencies> 41 42 <build> 43 <plugins> 44 <plugin> 45 <groupId>org.apache.maven.plugins</groupId> 46 <artifactId>maven-compiler-plugin</artifactId> 47 <version>${maven-compiler-plugin.version}</version> 48 <configuration> 49 <source>${maven-compiler-plugin.source}</source> 50 <target>${maven-compiler-plugin.target}</target> 51 </configuration> 52 </plugin> 53 <plugin> 54 <!-- Adding this plugin, so we don't need to add -Dexec.cleanupDaemonThreads=false in the mvn cmd line --> 55 <!-- to avoid the IllegalThreadStateException when running with Maven --> 56 <groupId>org.codehaus.mojo</groupId> 57 <artifactId>exec-maven-plugin</artifactId> 58 <version>${exec-maven-plugin.version}</version> 59 <configuration> 60 <cleanupDaemonThreads>false</cleanupDaemonThreads> 61 </configuration> 62 </plugin> 63 </plugins> 64 </build> 65 66 </project>
Para verificar se tudo está funcionando corretamente, você pode criar e executar um programa "Hello MongoDB!" simples. Em
src/main/java/com/mongodb/quickstart
, crie o arquivo HelloMongoDB.java
:1 package com.mongodb.quickstart; 2 3 public class HelloMongoDB { 4 5 public static void main(String[] args) { 6 System.out.println("Hello MongoDB!"); 7 } 8 }
Em seguida, compile e execute-o com seu IDE ou use a linha de comando no diretório raiz (onde está a pasta
src
):1 mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.HelloMongoDB"
O resultado deve ficar assim:
1 [INFO] Scanning for projects... 2 [INFO] 3 [INFO] --------------------< com.mongodb:java-quick-start >-------------------- 4 [INFO] Building java-quick-start 1.0-SNAPSHOT 5 [INFO] --------------------------------[ jar ]--------------------------------- 6 [INFO] 7 [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ java-quick-start --- 8 [INFO] Using 'UTF-8' encoding to copy filtered resources. 9 [INFO] Copying 1 resource 10 [INFO] 11 [INFO] --- maven-compiler-plugin:3.12.1:compile (default-compile) @ java-quick-start --- 12 [INFO] Nothing to compile - all classes are up to date. 13 [INFO] 14 [INFO] --- exec-maven-plugin:3.1.1:java (default-cli) @ java-quick-start --- 15 Hello MongoDB! 16 [INFO] ------------------------------------------------------------------------ 17 [INFO] BUILD SUCCESS 18 [INFO] ------------------------------------------------------------------------ 19 [INFO] Total time: 0.634 s 20 [INFO] Finished at: 2024-02-19T18:12:22+01:00 21 [INFO] ------------------------------------------------------------------------
Agora que nosso projeto Maven funciona e resolvemos nossas dependências, podemos começar a usar o MongoDB Atlas com Java.
Se você importou o conjunto de dados de amostra conforme sugerido na postagem do blog Quick Start Atlas, então, com o código Java que estamos prestes a criar, você poderá ver uma lista dos bancos de dados no conjunto de dados de amostra.
A primeira etapa é instanciar um
MongoClient
passando uma string de conexão do MongoDB Atlas para o método estático MongoClients.create()
. Isso estabelecerá uma conexão com o MongoDB Atlas usando a string de conexão. Em seguida, podemos recuperar a lista de bancos de dados neste cluster e imprimi-los para testar a conexão com o MongoDB.De acordo com as práticas recomendadas, também estou fazendo uma "verificação pré-voo" usando o comando admin
{ping: 1}
.Em
src/main/java/com/mongodb
, crie o arquivo Connection.java
:1 package com.mongodb.quickstart; 2 3 import com.mongodb.client.MongoClient; 4 import com.mongodb.client.MongoClients; 5 import org.bson.Document; 6 import org.bson.json.JsonWriterSettings; 7 8 import java.util.ArrayList; 9 import java.util.List; 10 11 public class Connection { 12 13 public static void main(String[] args) { 14 String connectionString = System.getProperty("mongodb.uri"); 15 try (MongoClient mongoClient = MongoClients.create(connectionString)) { 16 System.out.println("=> Connection successful: " + preFlightChecks(mongoClient)); 17 System.out.println("=> Print list of databases:"); 18 List<Document> databases = mongoClient.listDatabases().into(new ArrayList<>()); 19 databases.forEach(db -> System.out.println(db.toJson())); 20 } 21 } 22 23 static boolean preFlightChecks(MongoClient mongoClient) { 24 Document pingCommand = new Document("ping", 1); 25 Document response = mongoClient.getDatabase("admin").runCommand(pingCommand); 26 System.out.println("=> Print result of the '{ping: 1}' command."); 27 System.out.println(response.toJson(JsonWriterSettings.builder().indent(true).build())); 28 return response.get("ok", Number.class).intValue() == 1; 29 } 30 }
Como você pode ver, a string de conexão do MongoDB é recuperada das Propriedades do sistema, portanto, precisamos configurar isso. Depois de recuperar a string de conexão do MongoDB Atlas, você pode adicionar a propriedade do sistema
mongodb.uri
ao seu IDE. Esta é minha configuração com IntelliJ, por exemplo.Ou se você preferir usar o Maven na linha de comando, esta é a linha de comando equivalente que você pode executar no diretório raiz:
1 mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.Connection" -Dmongodb.uri="mongodb+srv://username:password@cluster0-abcde.mongodb.net/test?w=majority"
Observação: não se esqueça das aspas duplas em torno do URI do MongoDB para evitar surpresas do seu shell.
A saída padrão deve ser semelhante a esta:
1 {"name": "admin", "sizeOnDisk": 303104.0, "empty": false} 2 {"name": "config", "sizeOnDisk": 147456.0, "empty": false} 3 {"name": "local", "sizeOnDisk": 5.44731136E8, "empty": false} 4 {"name": "sample_airbnb", "sizeOnDisk": 5.761024E7, "empty": false} 5 {"name": "sample_geospatial", "sizeOnDisk": 1384448.0, "empty": false} 6 {"name": "sample_mflix", "sizeOnDisk": 4.583424E7, "empty": false} 7 {"name": "sample_supplies", "sizeOnDisk": 1339392.0, "empty": false} 8 {"name": "sample_training", "sizeOnDisk": 7.4801152E7, "empty": false} 9 {"name": "sample_weatherdata", "sizeOnDisk": 5103616.0, "empty": false}
Na seção Conectando com Java, criamos as classes
HelloMongoDB
e Connection
. Agora trabalharemos na classe Create
.Se você não configurou seu cluster gratuito no MongoDB Atlas, agora é um ótimo momento para fazê-lo. Obtenha as instruções para criar seu cluster.
No conjunto de dados de amostra, você pode encontrar o banco de dados
sample_training
, que contém uma coleção grades
. Cada documento nesta coleção representa as notas de um aluno para uma turma específica.1 MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.grades.findOne({student_id: 0, class_id: 339}) 2 { 3 "_id" : ObjectId("56d5f7eb604eb380b0d8d8ce"), 4 "student_id" : 0, 5 "scores" : [ 6 { 7 "type" : "exam", 8 "score" : 78.40446309504266 9 }, 10 { 11 "type" : "quiz", 12 "score" : 73.36224783231339 13 }, 14 { 15 "type" : "homework", 16 "score" : 46.980982486720535 17 }, 18 { 19 "type" : "homework", 20 "score" : 76.67556138656222 21 } 22 ], 23 "class_id" : 339 24 }
E aqui está a representação JSON estendida do mesmo aluno. Você pode recuperá-la no MongoDB Compass, nossa ferramenta GUI gratuita, se desejar.
O JSON estendido é a versão legível por humanos de um documento BSON sem perda de informações de tipo. Você pode ler mais sobre o driver Java e o BSON na documentação do driver Java do MongoDB.
1 { 2 "_id": { 3 "$oid": "56d5f7eb604eb380b0d8d8ce" 4 }, 5 "student_id": { 6 "$numberDouble": "0" 7 }, 8 "scores": [{ 9 "type": "exam", 10 "score": { 11 "$numberDouble": "78.40446309504266" 12 } 13 }, { 14 "type": "quiz", 15 "score": { 16 "$numberDouble": "73.36224783231339" 17 } 18 }, { 19 "type": "homework", 20 "score": { 21 "$numberDouble": "46.980982486720535" 22 } 23 }, { 24 "type": "homework", 25 "score": { 26 "$numberDouble": "76.67556138656222" 27 } 28 }], 29 "class_id": { 30 "$numberDouble": "339" 31 } 32 }
Como você pode ver, o MongoDB armazena documentos BSON e, para cada par de valores-chave, o BSON contém a chave e o valor junto com seu tipo. É assim que o MongoDB sabe que
class_id
é na verdade um duplo e não um número inteiro, o que não está explícito na representação do mongo shell deste documento.Já temos 10.000 alunos (
student_id
de 0 a 9999) nesta coleção e cada um deles fez 10 aulas diferentes, o que adiciona 100.000 documentos a esta coleção. Digamos que um novo aluno (student_id
10,000) acabou de chegar a esta universidade e recebeu um grupo de notas (aleatórias) na primeira aula. Vamos inserir esse novo documento do aluno usando Java e o driver Java do MongoDB.Nessa universidade, o
class_id
varia de 0 a 500, então posso usar qualquer valor aleatório entre 0 e 500.Em primeiro lugar, precisamos configurar nossa classe
Create
e acessar esta coleção sample_training.grades
.1 package com.mongodb.quickstart; 2 3 import com.mongodb.client.MongoClient; 4 import com.mongodb.client.MongoClients; 5 import com.mongodb.client.MongoCollection; 6 import com.mongodb.client.MongoDatabase; 7 import org.bson.Document; 8 9 public class Create { 10 11 public static void main(String[] args) { 12 try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { 13 14 MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); 15 MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); 16 17 } 18 } 19 }
Em segundo lugar, precisamos representar esse novo aluno em Java usando a classe
Document
.1 Random rand = new Random(); 2 Document student = new Document("_id", new ObjectId()); 3 student.append("student_id", 10000d) 4 .append("class_id", 1d) 5 .append("scores", List.of(new Document("type", "exam").append("score", rand.nextDouble() * 100), 6 new Document("type", "quiz").append("score", rand.nextDouble() * 100), 7 new Document("type", "homework").append("score", rand.nextDouble() * 100), 8 new Document("type", "homework").append("score", rand.nextDouble() * 100)));
Como você pode ver, reproduzimos o mesmo Modelo de dados Realm dos documentos existentes nessa coleção, pois nos certificamos de que
student_id
, class_id
e score
são todos duplos.Além disso, o driver Java teria gerado o campo
_id
com um ObjectId para nós se não tivéssemos criado explicitamente um aqui, mas é uma boa prática definir o _id
nós mesmos. Isso não mudará nossa vida no momento, mas faz mais sentido quando manipularmos diretamente os POJOs e quisermos criar uma REST API limpa. Estou fazendo isso em minha publicação de mapeamento de POJOs.Observe também que estamos inserindo um documento em uma coleção e em um banco de dados existentes, mas, se eles ainda não existissem, o MongoDB os criaria automaticamente na primeira vez que você inserisse um documento na coleção.
Por fim, podemos inserir esse documento.
1 gradesCollection.insertOne(student);
Aqui está a classe
Create
final para inserir um documento no MongoDB com todos os detalhes que mencionei acima.1 package com.mongodb.quickstart; 2 3 import com.mongodb.client.MongoClient; 4 import com.mongodb.client.MongoClients; 5 import com.mongodb.client.MongoCollection; 6 import com.mongodb.client.MongoDatabase; 7 import org.bson.Document; 8 import org.bson.types.ObjectId; 9 10 import java.util.List; 11 import java.util.Random; 12 13 public class Create { 14 15 public static void main(String[] args) { 16 try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { 17 18 MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); 19 MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); 20 21 Random rand = new Random(); 22 Document student = new Document("_id", new ObjectId()); 23 student.append("student_id", 10000d) 24 .append("class_id", 1d) 25 .append("scores", List.of(new Document("type", "exam").append("score", rand.nextDouble() * 100), 26 new Document("type", "quiz").append("score", rand.nextDouble() * 100), 27 new Document("type", "homework").append("score", rand.nextDouble() * 100), 28 new Document("type", "homework").append("score", rand.nextDouble() * 100))); 29 30 gradesCollection.insertOne(student); 31 } 32 } 33 }
Você pode executar essa classe com a seguinte linha de comando do Maven no diretório raiz ou usando seu IDE (veja acima para obter mais detalhes). Não se esqueça das aspas duplas em torno do URI do MongoDB para evitar surpresas.
1 mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.Create" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority"
1 { 2 "_id": { 3 "$oid": "5d97c375ded5651ea3462d0f" 4 }, 5 "student_id": { 6 "$numberDouble": "10000" 7 }, 8 "class_id": { 9 "$numberDouble": "1" 10 }, 11 "scores": [{ 12 "type": "exam", 13 "score": { 14 "$numberDouble": "4.615256396625178" 15 } 16 }, { 17 "type": "quiz", 18 "score": { 19 "$numberDouble": "73.06173415145801" 20 } 21 }, { 22 "type": "homework", 23 "score": { 24 "$numberDouble": "19.378205578990727" 25 } 26 }, { 27 "type": "homework", 28 "score": { 29 "$numberDouble": "82.3089189278531" 30 } 31 }] 32 }
Observe que a ordem dos campos é diferente do documento inicial com
"student_id": 0
.Poderíamos obter exatamente a mesma ordem se quiséssemos criando o documento assim.
1 Random rand = new Random(); 2 Document student = new Document("_id", new ObjectId()); 3 student.append("student_id", 10000d) 4 .append("scores", List.of(new Document("type", "exam").append("score", rand.nextDouble() * 100), 5 new Document("type", "quiz").append("score", rand.nextDouble() * 100), 6 new Document("type", "homework").append("score", rand.nextDouble() * 100), 7 new Document("type", "homework").append("score", rand.nextDouble() * 100))) 8 .append("class_id", 1d);
Mas se você fizer as coisas corretamente, isso não deve ter nenhum impacto em seu código e lógica, pois os campos em documentos JSON não são ordenados.
Um objeto é um conjunto não ordenado de pares de nome/valor.
Agora que sabemos como criar um documento, vamos aprender a inserir vários documentos.
Naturalmente, poderíamos apenas encapsular a operação
insert
anterior em um loop for
. De fato, se fizermos 10 loops nesse método, enviaremos 10 comandos de inserção para o cluster e esperaremos 10 confirmações de inserção. Como você pode imaginar, isso não seria muito eficiente, pois geraria muito mais comunicações TCP do que o necessário.Em vez disso, queremos encapsular nossos 10 documentos e enviá-los em uma chamada para o cluster e queremos receber apenas uma confirmação de inserção para toda a lista.
Vamos refatorar o código. Primeiro, vamos transformar o gerador aleatório em um campo
private static final
.1 private static final Random rand = new Random();
Vamos criar um método de fábrica de notas.
1 private static Document generateNewGrade(double studentId, double classId) { 2 List<Document> scores = List.of(new Document("type", "exam").append("score", rand.nextDouble() * 100), 3 new Document("type", "quiz").append("score", rand.nextDouble() * 100), 4 new Document("type", "homework").append("score", rand.nextDouble() * 100), 5 new Document("type", "homework").append("score", rand.nextDouble() * 100)); 6 return new Document("_id", new ObjectId()).append("student_id", studentId) 7 .append("class_id", classId) 8 .append("scores", scores); 9 }
E agora podemos usar isso para inserir 10 documentos de uma só vez.
1 List<Document> grades = new ArrayList<>(); 2 for (double classId = 1d; classId <= 10d; classId++) { 3 grades.add(generateNewGrade(10001d, classId)); 4 } 5 6 gradesCollection.insertMany(grades, new InsertManyOptions().ordered(false));
Como você pode ver, agora estamos agrupando nossos documentos de nota em uma lista e estamos enviando essa lista em uma única chamada com o método
insertMany
.Por padrão, o método
insertMany
insere os documentos em ordem e interrompe se ocorrer um erro durante o processo. Por exemplo, se você tentar inserir um novo documento com o mesmo _id
de um documento existente, obterá um DuplicateKeyException
.Portanto, com um
insertMany
ordenado, os últimos documentos da lista não seriam inseridos e o processo de inserção pararia e retornaria a exceção apropriada assim que ocorresse o erro.Como você pode ver aqui, esse não é o comportamento que queremos, pois todas as notas são completamente independentes umas das outras. Portanto, se uma delas falhar, queremos processar todas as notas e, por fim, voltar a uma exceção para as que falharam.
É por isso que você vê o segundo parâmetro
new InsertManyOptions().ordered(false)
, que é verdadeiro por padrão.Vamos refatorar um pouco o código e aqui está a classe
Create
final.1 package com.mongodb.quickstart; 2 3 import com.mongodb.client.MongoClient; 4 import com.mongodb.client.MongoClients; 5 import com.mongodb.client.MongoCollection; 6 import com.mongodb.client.MongoDatabase; 7 import com.mongodb.client.model.InsertManyOptions; 8 import org.bson.Document; 9 import org.bson.types.ObjectId; 10 11 import java.util.ArrayList; 12 import java.util.List; 13 import java.util.Random; 14 15 public class Create { 16 17 private static final Random rand = new Random(); 18 19 public static void main(String[] args) { 20 try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { 21 22 MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); 23 MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); 24 25 insertOneDocument(gradesCollection); 26 insertManyDocuments(gradesCollection); 27 } 28 } 29 30 private static void insertOneDocument(MongoCollection<Document> gradesCollection) { 31 gradesCollection.insertOne(generateNewGrade(10000d, 1d)); 32 System.out.println("One grade inserted for studentId 10000."); 33 } 34 35 private static void insertManyDocuments(MongoCollection<Document> gradesCollection) { 36 List<Document> grades = new ArrayList<>(); 37 for (double classId = 1d; classId <= 10d; classId++) { 38 grades.add(generateNewGrade(10001d, classId)); 39 } 40 41 gradesCollection.insertMany(grades, new InsertManyOptions().ordered(false)); 42 System.out.println("Ten grades inserted for studentId 10001."); 43 } 44 45 private static Document generateNewGrade(double studentId, double classId) { 46 List<Document> scores = List.of(new Document("type", "exam").append("score", rand.nextDouble() * 100), 47 new Document("type", "quiz").append("score", rand.nextDouble() * 100), 48 new Document("type", "homework").append("score", rand.nextDouble() * 100), 49 new Document("type", "homework").append("score", rand.nextDouble() * 100)); 50 return new Document("_id", new ObjectId()).append("student_id", studentId) 51 .append("class_id", classId) 52 .append("scores", scores); 53 } 54 }
Como lembrete, cada operação de gravação (criar, substituir, atualizar, excluir) executada em um único documento é ACID no MongoDB. O que significa que
insertMany
não é ACID por padrão, mas boas notícias, como o MongoDB 4.0, podemos envolver essa chamada em uma ACID transaction de vários documentos para torná-la totalmente ACID. Eu explico isso com mais detalhes em meu blog sobre ACID transaction de vários documentos.Criamos a classe
Create
. Agora trabalharemos na classeRead
.Escrevemos 11 novas notas, uma para o aluno com
{"student_id": 10000}
e 10 para o aluno com {"student_id": 10001}
na coleção sample_training.grades
.Como lembrete, aqui estão as notas do
{"student_id": 10000}
.1 MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.grades.findOne({"student_id":10000}) 2 { 3 "_id" : ObjectId("5daa0e274f52b44cfea94652"), 4 "student_id" : 10000, 5 "class_id" : 1, 6 "scores" : [ 7 { 8 "type" : "exam", 9 "score" : 39.25175977753478 10 }, 11 { 12 "type" : "quiz", 13 "score" : 80.2908713167313 14 }, 15 { 16 "type" : "homework", 17 "score" : 63.5444978481843 18 }, 19 { 20 "type" : "homework", 21 "score" : 82.35202261582563 22 } 23 ] 24 }
Também discutimos os BSON types e observamos que
student_id
e class_id
são duplos.O MongoDB trata alguns tipos como equivalentes para fins de comparação. Por exemplo, tipos numéricos passam por conversão antes da comparação.
Portanto, não se surpreenda se eu filtrar com um número inteiro e corresponder a um documento que contenha um número duplo, por exemplo. Se quiser filtrar documentos por tipos de valor, você pode usar o operador $type.
Você pode ler mais sobre colchetes de tipo e comparação e ordem de classificação em nossa documentação.
Vamos ler o documento acima. Para isso, usaremos o método
find
, passando um filtro para ajudar a identificar o documento que queremos encontrar.Crie uma classe
Read
no pacote com.mongodb.quickstart
com este código:1 package com.mongodb.quickstart; 2 3 import com.mongodb.client.*; 4 import org.bson.Document; 5 6 import java.util.ArrayList; 7 import java.util.List; 8 9 import static com.mongodb.client.model.Filters.*; 10 import static com.mongodb.client.model.Projections.*; 11 import static com.mongodb.client.model.Sorts.descending; 12 13 public class Read { 14 15 public static void main(String[] args) { 16 try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { 17 MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); 18 MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); 19 20 // find one document with new Document 21 Document student1 = gradesCollection.find(new Document("student_id", 10000)).first(); 22 System.out.println("Student 1: " + student1.toJson()); 23 } 24 } 25 }
Além disso, certifique-se de configurar seu
mongodb.uri
nas propriedades do sistema usando seu IDE se quiser executar este código em seu IDE favorito.Como alternativa, você pode usar esta linha de comando do Maven em seu projeto raiz (onde está a pasta
src
):1 mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.Read" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority"
A saída padrão deve ser:
1 Student 1: {"_id": {"$oid": "5daa0e274f52b44cfea94652"}, 2 "student_id": 10000.0, 3 "class_id": 1.0, 4 "scores": [ 5 {"type": "exam", "score": 39.25175977753478}, 6 {"type": "quiz", "score": 80.2908713167313}, 7 {"type": "homework", "score": 63.5444978481843}, 8 {"type": "homework", "score": 82.35202261582563} 9 ] 10 }
O driver do MongoDB vem com alguns auxiliares para facilitar a gravação dessas queries. Aqui está uma query equivalente usando o método
Filters.eq()
.1 gradesCollection.find(eq("student_id", 10000)).first();
Obviamente, usei uma importação estática para tornar o código o mais compacto e fácil de ler possível.
1 import static com.mongodb.client.model.Filters.eq;
No exemplo anterior, o benefício desses auxiliares não é óbvio, mas deixe-me mostrar outro exemplo em que estou pesquisando todas as notas com um student_id maior ou igual a 10.000.
1 // without helpers 2 gradesCollection.find(new Document("student_id", new Document("$gte", 10000))); 3 // with the Filters.gte() helper 4 gradesCollection.find(gte("student_id", 10000));
Como você pode ver, estou usando o operador
$gte
para gravar essa query. Você pode saber mais sobre todos os diferentes operadores de query na documentação do MongoDB.O método
find
retorna um objeto que implementa a interface FindIterable
, que, em última análise, estende a interface Iterable
, para que possamos usar um iterador para percorrer a lista de documentos que estamos recebendo do MongoDB:1 FindIterable<Document> iterable = gradesCollection.find(gte("student_id", 10000)); 2 MongoCursor<Document> cursor = iterable.iterator(); 3 System.out.println("Student list with cursor: "); 4 while (cursor.hasNext()) { 5 System.out.println(cursor.next().toJson()); 6 }
As listas geralmente são mais fáceis de manipular do que os iteradores, portanto, também podemos fazer isso para recuperar diretamente um
ArrayList<Document>
:1 List<Document> studentList = gradesCollection.find(gte("student_id", 10000)).into(new ArrayList<>()); 2 System.out.println("Student list with an ArrayList:"); 3 for (Document student : studentList) { 4 System.out.println(student.toJson()); 5 }
Também poderíamos usar
Consumer
, que é uma interface funcional:1 Consumer<Document> printConsumer = document -> System.out.println(document.toJson()); 2 gradesCollection.find(gte("student_id", 10000)).forEach(printConsumer);
Como vimos acima com o exemplo
Iterator
, o MongoDB aproveita os cursores para iterar por seu conjunto de resultados.Se você já está familiarizado com os cursores no mongo shell, sabe que podemos aplicar transformações a ele. Um cursor pode ser classificado e os documentos que ele contém podem ser transformados usando uma projeção. Além disso, uma vez que o cursor é classificado, podemos optar por ignorar alguns documentos e limitar o número de documentos na saída. Isso é muito útil para implementar a paginação em seu frontend, por exemplo.
Vamos combinar tudo o que aprendemos em uma única query:
1 List<Document> docs = gradesCollection.find(and(eq("student_id", 10001), lte("class_id", 5))) 2 .projection(fields(excludeId(), 3 include("class_id", 4 "student_id"))) 5 .sort(descending("class_id")) 6 .skip(2) 7 .limit(2) 8 .into(new ArrayList<>()); 9 10 System.out.println("Student sorted, skipped, limited and projected: "); 11 for (Document student : docs) { 12 System.out.println(student.toJson()); 13 }
Esta é a saída que obtemos:
1 {"student_id": 10001.0, "class_id": 3.0} 2 {"student_id": 10001.0, "class_id": 2.0}
Lembre-se de que os documentos são retornados na ordem natural; portanto, se quiser que o resultado seja ordenado, será necessário classificar os cursores para garantir que não haja aleatoriedade no algoritmo.
Para tornar minha última query eficiente, devo criar este índice:
1 db.grades.createIndex({"student_id": 1, "class_id": -1})
1 "winningPlan" : { 2 "stage" : "LIMIT", 3 "limitAmount" : 2, 4 "inputStage" : { 5 "stage" : "PROJECTION_COVERED", 6 "transformBy" : { 7 "_id" : 0, 8 "class_id" : 1, 9 "student_id" : 1 10 }, 11 "inputStage" : { 12 "stage" : "SKIP", 13 "skipAmount" : 2, 14 "inputStage" : { 15 "stage" : "IXSCAN", 16 "keyPattern" : { 17 "student_id" : 1, 18 "class_id" : -1 19 }, 20 "indexName" : "student_id_1_class_id_-1", 21 "isMultiKey" : false, 22 "multiKeyPaths" : { 23 "student_id" : [ ], 24 "class_id" : [ ] 25 }, 26 "isUnique" : false, 27 "isSparse" : false, 28 "isPartial" : false, 29 "indexVersion" : 2, 30 "direction" : "forward", 31 "indexBounds" : { 32 "student_id" : [ 33 "[10001.0, 10001.0]" 34 ], 35 "class_id" : [ 36 "[5.0, -inf.0]" 37 ] 38 } 39 } 40 } 41 } 42 }
Com esse índice, podemos ver que não temos nenhum estágio SORT, portanto, não estamos fazendo uma classificação na memória, pois os documentos já estão classificados "de graça" e retornados na ordem do índice.
Além disso, podemos ver que não temos nenhum estágio FETCH, então esta é uma query coberta, o tipo de query mais eficiente que você pode executar no MongoDB. De fato, todas as informações que estamos retornando no final já estão no índice, então o índice em si contém tudo o que precisamos para responder a essa query.
1 package com.mongodb.quickstart; 2 3 import com.mongodb.client.*; 4 import org.bson.Document; 5 6 import java.util.ArrayList; 7 import java.util.List; 8 import java.util.function.Consumer; 9 10 import static com.mongodb.client.model.Filters.*; 11 import static com.mongodb.client.model.Projections.*; 12 import static com.mongodb.client.model.Sorts.descending; 13 14 public class Read { 15 16 public static void main(String[] args) { 17 try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { 18 MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); 19 MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); 20 21 // find one document with new Document 22 Document student1 = gradesCollection.find(new Document("student_id", 10000)).first(); 23 System.out.println("Student 1: " + student1.toJson()); 24 25 // find one document with Filters.eq() 26 Document student2 = gradesCollection.find(eq("student_id", 10000)).first(); 27 System.out.println("Student 2: " + student2.toJson()); 28 29 // find a list of documents and iterate throw it using an iterator. 30 FindIterable<Document> iterable = gradesCollection.find(gte("student_id", 10000)); 31 MongoCursor<Document> cursor = iterable.iterator(); 32 System.out.println("Student list with a cursor: "); 33 while (cursor.hasNext()) { 34 System.out.println(cursor.next().toJson()); 35 } 36 37 // find a list of documents and use a List object instead of an iterator 38 List<Document> studentList = gradesCollection.find(gte("student_id", 10000)).into(new ArrayList<>()); 39 System.out.println("Student list with an ArrayList:"); 40 for (Document student : studentList) { 41 System.out.println(student.toJson()); 42 } 43 44 // find a list of documents and print using a consumer 45 System.out.println("Student list using a Consumer:"); 46 Consumer<Document> printConsumer = document -> System.out.println(document.toJson()); 47 gradesCollection.find(gte("student_id", 10000)).forEach(printConsumer); 48 49 // find a list of documents with sort, skip, limit and projection 50 List<Document> docs = gradesCollection.find(and(eq("student_id", 10001), lte("class_id", 5))) 51 .projection(fields(excludeId(), include("class_id", "student_id"))) 52 .sort(descending("class_id")) 53 .skip(2) 54 .limit(2) 55 .into(new ArrayList<>()); 56 57 System.out.println("Student sorted, skipped, limited and projected:"); 58 for (Document student : docs) { 59 System.out.println(student.toJson()); 60 } 61 } 62 } 63 }
Vamos editar o documento com
{student_id: 10000}
. Para isso, usaremos o método updateOne
.Crie uma classe
Update
no pacote com.mongodb.quickstart
com este código:1 package com.mongodb.quickstart; 2 3 import com.mongodb.client.MongoClient; 4 import com.mongodb.client.MongoClients; 5 import com.mongodb.client.MongoCollection; 6 import com.mongodb.client.MongoDatabase; 7 import com.mongodb.client.model.FindOneAndUpdateOptions; 8 import com.mongodb.client.model.ReturnDocument; 9 import com.mongodb.client.model.UpdateOptions; 10 import com.mongodb.client.result.UpdateResult; 11 import org.bson.Document; 12 import org.bson.conversions.Bson; 13 import org.bson.json.JsonWriterSettings; 14 15 import static com.mongodb.client.model.Filters.and; 16 import static com.mongodb.client.model.Filters.eq; 17 import static com.mongodb.client.model.Updates.*; 18 19 public class Update { 20 21 public static void main(String[] args) { 22 JsonWriterSettings prettyPrint = JsonWriterSettings.builder().indent(true).build(); 23 24 try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { 25 MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); 26 MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); 27 28 // update one document 29 Bson filter = eq("student_id", 10000); 30 Bson updateOperation = set("comment", "You should learn MongoDB!"); 31 UpdateResult updateResult = gradesCollection.updateOne(filter, updateOperation); 32 System.out.println("=> Updating the doc with {\"student_id\":10000}. Adding comment."); 33 System.out.println(gradesCollection.find(filter).first().toJson(prettyPrint)); 34 System.out.println(updateResult); 35 } 36 } 37 }
Como você pode ver neste exemplo, o método
updateOne
recebe dois parâmetros:- O primeiro é o filtro que identifica o documento que queremos atualizar.
- A segunda é a operação de atualização. Aqui, estamos definindo um novo campo
comment
com o valor"You should learn MongoDB!"
.
Para executar esse programa, certifique-se de configurar seu
mongodb.uri
nas propriedades do sistema usando seu IDE se quiser executar esse código em seu IDE favorito (consulte acima para obter mais detalhes).Como alternativa, você pode usar esta linha de comando do Maven em seu projeto raiz (onde está a pasta
src
):1 mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.Update" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority"
A saída padrão deve ser semelhante a esta:
1 => Updating the doc with {"student_id":10000}. Adding comment. 2 { 3 "_id": { 4 "$oid": "5dd5c1f351f97d4a034109ed" 5 }, 6 "student_id": 10000.0, 7 "class_id": 1.0, 8 "scores": [ 9 { 10 "type": "exam", 11 "score": 21.580800815091415 12 }, 13 { 14 "type": "quiz", 15 "score": 87.66967927111044 16 }, 17 { 18 "type": "homework", 19 "score": 96.4060480668003 20 }, 21 { 22 "type": "homework", 23 "score": 75.44966835508427 24 } 25 ], 26 "comment": "You should learn MongoDB!" 27 } 28 AcknowledgedUpdateResult{matchedCount=1, modifiedCount=1, upsertedId=null}
Um upsert é uma mistura entre uma operação de inserção e uma de atualização. Isso acontece quando você deseja atualizar um documento, supondo que ele exista, mas na verdade ele ainda não existe em seu banco de dados.
No MongoDB, você pode definir uma opção para criar esse documento em tempo real e continuar com sua operação de atualização. Esta é uma operação upsert.
Neste exemplo, quero adicionar um comentário às notas do aluno 10002 para a aula 10, mas este documento ainda não existe.
1 filter = and(eq("student_id", 10002d), eq("class_id", 10d)); 2 updateOperation = push("comments", "You will learn a lot if you read the MongoDB blog!"); 3 UpdateOptions options = new UpdateOptions().upsert(true); 4 updateResult = gradesCollection.updateOne(filter, updateOperation, options); 5 System.out.println("\n=> Upsert document with {\"student_id\":10002.0, \"class_id\": 10.0} because it doesn't exist yet."); 6 System.out.println(updateResult); 7 System.out.println(gradesCollection.find(filter).first().toJson(prettyPrint));
Como você pode ver, estou usando o terceiro parâmetro da operação de atualização para definir a opção upsert como verdadeira.
Também estou usando o método estático
Updates.push()
para inserir um novo valor em meu array comments
que ainda não existe, portanto, estou criando um array de um elemento nesse caso.Esta é a saída que obtemos:
1 => Upsert document with {"student_id":10002.0, "class_id": 10.0} because it doesn't exist yet. 2 AcknowledgedUpdateResult{matchedCount=0, modifiedCount=0, upsertedId=BsonObjectId{value=5ddeb7b7224ad1d5cfab3733}} 3 { 4 "_id": { 5 "$oid": "5ddeb7b7224ad1d5cfab3733" 6 }, 7 "class_id": 10.0, 8 "student_id": 10002.0, 9 "comments": [ 10 "You will learn a lot if you read the MongoDB blog!" 11 ] 12 }
Da mesma forma que consegui atualizar um documento com
updateOne()
, posso atualizar vários documentos com updateMany()
.1 filter = eq("student_id", 10001); 2 updateResult = gradesCollection.updateMany(filter, updateOperation); 3 System.out.println("\n=> Updating all the documents with {\"student_id\":10001}."); 4 System.out.println(updateResult);
Neste exemplo, estou usando o mesmo
updateOperation
anterior, portanto, estou criando uma nova array de um elemento comments
nesses documentos 10.Aqui está o resultado:
1 => Updating all the documents with {"student_id":10001}. 2 AcknowledgedUpdateResult{matchedCount=10, modifiedCount=10, upsertedId=null}
Por fim, temos um último método muito útil disponível no MongoDB Java Driver:
findOneAndUpdate()
.Na maioria dos aplicativos da web, quando um usuário atualiza algo, ele deseja ver essa atualização refletida em sua página da web. Sem o método
findOneAndUpdate()
, você teria que executar uma operação de atualização e, em seguida, buscar o documento com uma operação de localização para garantir que está imprimindo a versão mais recente desse objeto na página da web.O método
findOneAndUpdate()
permite combinar essas duas operações em uma.1 // findOneAndUpdate 2 filter = eq("student_id", 10000); 3 Bson update1 = inc("x", 10); // increment x by 10. As x doesn't exist yet, x=10. 4 Bson update2 = rename("class_id", "new_class_id"); // rename variable "class_id" in "new_class_id". 5 Bson update3 = mul("scores.0.score", 2); // multiply the first score in the array by 2. 6 Bson update4 = addToSet("comments", "This comment is uniq"); // creating an array with a comment. 7 Bson update5 = addToSet("comments", "This comment is uniq"); // using addToSet so no effect. 8 Bson updates = combine(update1, update2, update3, update4, update5); 9 // returns the old version of the document before the update. 10 Document oldVersion = gradesCollection.findOneAndUpdate(filter, updates); 11 System.out.println("\n=> FindOneAndUpdate operation. Printing the old version by default:"); 12 System.out.println(oldVersion.toJson(prettyPrint)); 13 14 // but I can also request the new version 15 filter = eq("student_id", 10001); 16 FindOneAndUpdateOptions optionAfter = new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER); 17 Document newVersion = gradesCollection.findOneAndUpdate(filter, updates, optionAfter); 18 System.out.println("\n=> FindOneAndUpdate operation. But we can also ask for the new version of the doc:"); 19 System.out.println(newVersion.toJson(prettyPrint));
Aqui está o resultado:
1 => FindOneAndUpdate operation. Printing the old version by default: 2 { 3 "_id": { 4 "$oid": "5dd5d46544fdc35505a8271b" 5 }, 6 "student_id": 10000.0, 7 "class_id": 1.0, 8 "scores": [ 9 { 10 "type": "exam", 11 "score": 69.52994626959251 12 }, 13 { 14 "type": "quiz", 15 "score": 87.27457417188077 16 }, 17 { 18 "type": "homework", 19 "score": 83.40970667948744 20 }, 21 { 22 "type": "homework", 23 "score": 40.43663797673247 24 } 25 ], 26 "comment": "You should learn MongoDB!" 27 } 28 29 => FindOneAndUpdate operation. But we can also ask for the new version of the doc: 30 { 31 "_id": { 32 "$oid": "5dd5d46544fdc35505a82725" 33 }, 34 "student_id": 10001.0, 35 "scores": [ 36 { 37 "type": "exam", 38 "score": 138.42535412437857 39 }, 40 { 41 "type": "quiz", 42 "score": 84.66740178906916 43 }, 44 { 45 "type": "homework", 46 "score": 36.773091359279675 47 }, 48 { 49 "type": "homework", 50 "score": 14.90842128691825 51 } 52 ], 53 "comments": [ 54 "You will learn a lot if you read the MongoDB blog!", 55 "This comment is uniq" 56 ], 57 "new_class_id": 10.0, 58 "x": 10 59 }
Como você pode ver neste exemplo, é possível escolher qual versão do documento você deseja retornar usando a opção apropriada.
Também usei este exemplo para mostrar vários operadores de atualização:
set
definirá um valor.inc
incrementará um valor.rename
renomeará um campo.mul
multiplicará o valor pelo número fornecido.addToSet
é semelhante ao push, mas só colocará o valor no array se o valor ainda não existir.
1 package com.mongodb.quickstart; 2 3 import com.mongodb.client.MongoClient; 4 import com.mongodb.client.MongoClients; 5 import com.mongodb.client.MongoCollection; 6 import com.mongodb.client.MongoDatabase; 7 import com.mongodb.client.model.FindOneAndUpdateOptions; 8 import com.mongodb.client.model.ReturnDocument; 9 import com.mongodb.client.model.UpdateOptions; 10 import com.mongodb.client.result.UpdateResult; 11 import org.bson.Document; 12 import org.bson.conversions.Bson; 13 import org.bson.json.JsonWriterSettings; 14 15 import static com.mongodb.client.model.Filters.and; 16 import static com.mongodb.client.model.Filters.eq; 17 import static com.mongodb.client.model.Updates.*; 18 19 public class Update { 20 21 public static void main(String[] args) { 22 JsonWriterSettings prettyPrint = JsonWriterSettings.builder().indent(true).build(); 23 24 try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { 25 MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); 26 MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); 27 28 // update one document 29 Bson filter = eq("student_id", 10000); 30 Bson updateOperation = set("comment", "You should learn MongoDB!"); 31 UpdateResult updateResult = gradesCollection.updateOne(filter, updateOperation); 32 System.out.println("=> Updating the doc with {\"student_id\":10000}. Adding comment."); 33 System.out.println(gradesCollection.find(filter).first().toJson(prettyPrint)); 34 System.out.println(updateResult); 35 36 // upsert 37 filter = and(eq("student_id", 10002d), eq("class_id", 10d)); 38 updateOperation = push("comments", "You will learn a lot if you read the MongoDB blog!"); 39 UpdateOptions options = new UpdateOptions().upsert(true); 40 updateResult = gradesCollection.updateOne(filter, updateOperation, options); 41 System.out.println("\n=> Upsert document with {\"student_id\":10002.0, \"class_id\": 10.0} because it doesn't exist yet."); 42 System.out.println(updateResult); 43 System.out.println(gradesCollection.find(filter).first().toJson(prettyPrint)); 44 45 // update many documents 46 filter = eq("student_id", 10001); 47 updateResult = gradesCollection.updateMany(filter, updateOperation); 48 System.out.println("\n=> Updating all the documents with {\"student_id\":10001}."); 49 System.out.println(updateResult); 50 51 // findOneAndUpdate 52 filter = eq("student_id", 10000); 53 Bson update1 = inc("x", 10); // increment x by 10. As x doesn't exist yet, x=10. 54 Bson update2 = rename("class_id", "new_class_id"); // rename variable "class_id" in "new_class_id". 55 Bson update3 = mul("scores.0.score", 2); // multiply the first score in the array by 2. 56 Bson update4 = addToSet("comments", "This comment is uniq"); // creating an array with a comment. 57 Bson update5 = addToSet("comments", "This comment is uniq"); // using addToSet so no effect. 58 Bson updates = combine(update1, update2, update3, update4, update5); 59 // returns the old version of the document before the update. 60 Document oldVersion = gradesCollection.findOneAndUpdate(filter, updates); 61 System.out.println("\n=> FindOneAndUpdate operation. Printing the old version by default:"); 62 System.out.println(oldVersion.toJson(prettyPrint)); 63 64 // but I can also request the new version 65 filter = eq("student_id", 10001); 66 FindOneAndUpdateOptions optionAfter = new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER); 67 Document newVersion = gradesCollection.findOneAndUpdate(filter, updates, optionAfter); 68 System.out.println("\n=> FindOneAndUpdate operation. But we can also ask for the new version of the doc:"); 69 System.out.println(newVersion.toJson(prettyPrint)); 70 } 71 } 72 }
Vamos excluir o documento acima. Para isso, usaremos o método
deleteOne
.Crie uma classe
Delete
no pacote com.mongodb.quickstart
com este código:1 package com.mongodb.quickstart; 2 3 import com.mongodb.client.MongoClient; 4 import com.mongodb.client.MongoClients; 5 import com.mongodb.client.MongoCollection; 6 import com.mongodb.client.MongoDatabase; 7 import com.mongodb.client.result.DeleteResult; 8 import org.bson.Document; 9 import org.bson.conversions.Bson; 10 11 import static com.mongodb.client.model.Filters.eq; 12 import static com.mongodb.client.model.Filters.gte; 13 14 public class Delete { 15 16 public static void main(String[] args) { 17 18 try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { 19 MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); 20 MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); 21 22 // delete one document 23 Bson filter = eq("student_id", 10000); 24 DeleteResult result = gradesCollection.deleteOne(filter); 25 System.out.println(result); 26 } 27 } 28 }
Como você pode ver neste exemplo, o método
deleteOne
usa apenas um parâmetro: um filtro, assim como a operação find()
.Para executar esse programa, certifique-se de configurar seu
mongodb.uri
nas propriedades do sistema usando seu IDE se quiser executar esse código em seu IDE favorito (consulte acima para obter mais detalhes).Como alternativa, você pode usar esta linha de comando do Maven em seu projeto raiz (onde está a pasta
src
):1 mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.Delete" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority"
A saída padrão deve ser semelhante a esta:
1 AcknowledgedDeleteResult{deletedCount=1}
Você se apegou emocionalmente ao seu documento e quer uma chance de vê-lo uma última vez antes que seja tarde demais? Temos o que você precisa.
O método
findOneAndDelete()
permite recuperar um documento e excluí-lo em uma única operação atômica.Veja como funciona:
1 Bson filter = eq("student_id", 10002); 2 Document doc = gradesCollection.findOneAndDelete(filter); 3 System.out.println(doc.toJson(JsonWriterSettings.builder().indent(true).build()));
Esta é a saída que obtemos:
1 { 2 "_id": { 3 "$oid": "5ddec378224ad1d5cfac02b8" 4 }, 5 "class_id": 10.0, 6 "student_id": 10002.0, 7 "comments": [ 8 "You will learn a lot if you read the MongoDB blog!" 9 ] 10 }
Desta vez, usaremos
deleteMany()
em vez de deleteOne()
e usaremos um filtro diferente para corresponder a mais documentos.1 Bson filter = gte("student_id", 10000); 2 DeleteResult result = gradesCollection.deleteMany(filter); 3 System.out.println(result);
Esta é a saída que obtemos:
1 AcknowledgedDeleteResult{deletedCount=10}
A exclusão de todos os documentos de uma coleção não excluirá a coleção em si, pois uma coleção também contém metadados, como as definições de índice ou a distribuição de blocos, se sua coleção for fragmentada, por exemplo.
Se quiser remover a coleção inteira e todos os metadados associados a ela, será necessário usar o método
drop()
.1 gradesCollection.drop();
1 package com.mongodb.quickstart; 2 3 import com.mongodb.client.MongoClient; 4 import com.mongodb.client.MongoClients; 5 import com.mongodb.client.MongoCollection; 6 import com.mongodb.client.MongoDatabase; 7 import com.mongodb.client.result.DeleteResult; 8 import org.bson.Document; 9 import org.bson.conversions.Bson; 10 import org.bson.json.JsonWriterSettings; 11 12 import static com.mongodb.client.model.Filters.eq; 13 import static com.mongodb.client.model.Filters.gte; 14 15 public class Delete { 16 17 public static void main(String[] args) { 18 try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { 19 MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); 20 MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); 21 22 // delete one document 23 Bson filter = eq("student_id", 10000); 24 DeleteResult result = gradesCollection.deleteOne(filter); 25 System.out.println(result); 26 27 // findOneAndDelete operation 28 filter = eq("student_id", 10002); 29 Document doc = gradesCollection.findOneAndDelete(filter); 30 System.out.println(doc.toJson(JsonWriterSettings.builder().indent(true).build())); 31 32 // delete many documents 33 filter = gte("student_id", 10000); 34 result = gradesCollection.deleteMany(filter); 35 System.out.println(result); 36 37 // delete the entire collection and its metadata (indexes, chunk metadata, etc). 38 gradesCollection.drop(); 39 } 40 } 41 }
Com esta publicação no blog, abordamos todas as operações básicas, como criação e leitura, e também vimos como podemos usar facilmente funções poderosas disponíveis no driver Java para MongoDB. Você pode encontrar os links para as outras publicações no blog desta série logo abaixo.
Se você quiser aprender mais e afundar seu conhecimento com mais rapidez, recomendamos que consulte o "Caminho do desenvolvedor MongoDB Java", disponível gratuitamente na MongoDB University.