From fb303c45b38a57e0ac7ee683e76a6e6faa3fd00c Mon Sep 17 00:00:00 2001 From: Peter Hertkorn <peter.hertkorn@reutlingen-university.de> Date: Sun, 3 Nov 2024 21:45:30 +0100 Subject: [PATCH] Initial commit --- .gitignore | 4 + LICENSE | 201 ++++++++++++++++++ README.md | 110 ++++++++++ pom.xml | 66 ++++++ .../quickstart/AggregationFramework.java | 72 +++++++ .../com/mongodb/quickstart/Connection.java | 30 +++ .../java/com/mongodb/quickstart/Create.java | 54 +++++ .../java/com/mongodb/quickstart/Delete.java | 41 ++++ .../com/mongodb/quickstart/MappingPOJO.java | 62 ++++++ .../java/com/mongodb/quickstart/Read.java | 63 ++++++ .../java/com/mongodb/quickstart/Update.java | 72 +++++++ .../com/mongodb/quickstart/models/Grade.java | 81 +++++++ .../com/mongodb/quickstart/models/Score.java | 51 +++++ src/main/resources/logback.xml | 10 + 14 files changed, 917 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/com/mongodb/quickstart/AggregationFramework.java create mode 100644 src/main/java/com/mongodb/quickstart/Connection.java create mode 100644 src/main/java/com/mongodb/quickstart/Create.java create mode 100644 src/main/java/com/mongodb/quickstart/Delete.java create mode 100644 src/main/java/com/mongodb/quickstart/MappingPOJO.java create mode 100644 src/main/java/com/mongodb/quickstart/Read.java create mode 100644 src/main/java/com/mongodb/quickstart/Update.java create mode 100644 src/main/java/com/mongodb/quickstart/models/Grade.java create mode 100644 src/main/java/com/mongodb/quickstart/models/Score.java create mode 100644 src/main/resources/logback.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4b78738 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*iml +.idea/ +target/ +master_key.txt diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3f8b305 --- /dev/null +++ b/README.md @@ -0,0 +1,110 @@ +# Java Quick Start Project + +This repository contains code samples for the Quick Start blog post series. + +You can read more about the Quick Start series on the [MongoDB Developer Hub](https://www.mongodb.com/developer/). + +- [MongoDB & Java - CRUD Operations Tutorial](https://www.mongodb.com/developer/languages/java/java-setup-crud-operations/) +- [Java - Mapping POJOs](https://www.mongodb.com/developer/languages/java/java-mapping-pojos/) +- [Java - Aggregation Pipeline](https://www.mongodb.com/developer/languages/java/java-aggregation-pipeline/) +- [Java - Change Streams](https://www.mongodb.com/developer/languages/java/java-change-streams/) +- [Java - Client Side Field Level Encryption](https://www.mongodb.com/developer/languages/java/java-client-side-field-level-encryption/) +- [Java - Multi-Doc ACID Transactions](https://www.mongodb.com/developer/languages/java/java-multi-doc-acid-transactions/) + +# MongoDB Cluster + +To get started with MongoDB Atlas and get a free cluster read [this blog post](https://developer.mongodb.com/quickstart/free-atlas-cluster). + +# Requirements + +- Java 21 +- Maven 3.8.7. + +# Command lines + +- Compile: + +```sh +mvn clean compile +``` + +- Run the `HelloMongoDB` class: + +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.HelloMongoDB" +``` +- Run the `Connection` class: + +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.Connection" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" +``` + +- Run the `Create` class: + +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.Create" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" +``` + +- Run the `Read` class: + +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.Read" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" +``` + +- Run the `Update` class: + +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.Update" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" +``` + +- Run the `Delete` class: + +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.Delete" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" +``` + +- Run the `MappingPOJO` class: + +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.MappingPOJO" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" +``` + +- Run the `AggregationFramework` class: + +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.AggregationFramework" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" +``` + +- Run the `ChangeStreams` class: + +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.ChangeStreams" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" +``` + +- Run the `ClientSideFieldLevelEncryption` class: +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.csfle.ClientSideFieldLevelEncryption" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" +``` + +### Transactions + +Always start the `ChangeStreams` class in the `transactions` package first because it creates the `product` collection with the required JSON Schema. See the related blog post. + +- Run the `ChangeStreams` class: + +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.transactions.ChangeStreams" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" +``` + +- Run the `Transactions` class: + +```sh +mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.transactions.Transactions" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" +``` + +# Author + +Maxime Beugnet +- maxime@mongodb.com +- MaBeuLux88 on [GitHub](https://github.com/mabeulux88) +- MaBeuLux88 in the [MongoDB Developer Community forum](https://www.mongodb.com/community/forums/u/MaBeuLux88/summary). diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..bc21273 --- /dev/null +++ b/pom.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>com.mongodb</groupId> + <artifactId>java-quick-start</artifactId> + <version>1.0-SNAPSHOT</version> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven-compiler-plugin.source>21</maven-compiler-plugin.source> + <maven-compiler-plugin.target>21</maven-compiler-plugin.target> + <maven-compiler-plugin.version>3.12.1</maven-compiler-plugin.version> + <mongodb-driver-sync.version>5.0.0</mongodb-driver-sync.version> + <mongodb-crypt.version>1.8.0</mongodb-crypt.version> + <!-- Keeping 1.2.13 until mongodb-crypt makes slf4j-api an optional dependency --> + <!-- https://jira.mongodb.org/browse/MONGOCRYPT-602 --> + <logback-classic.version>1.2.13</logback-classic.version> + <exec-maven-plugin.version>3.1.1</exec-maven-plugin.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.mongodb</groupId> + <artifactId>mongodb-driver-sync</artifactId> + <version>${mongodb-driver-sync.version}</version> + </dependency> + <dependency> + <groupId>org.mongodb</groupId> + <artifactId>mongodb-crypt</artifactId> + <version>${mongodb-crypt.version}</version> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>${logback-classic.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>${maven-compiler-plugin.version}</version> + <configuration> + <source>${maven-compiler-plugin.source}</source> + <target>${maven-compiler-plugin.target}</target> + </configuration> + </plugin> + <plugin> + <!-- Adding this plugin, so we don't need to add -Dexec.cleanupDaemonThreads=false in the mvn cmd line --> + <!-- to avoid the IllegalThreadStateException when running with Maven --> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>${exec-maven-plugin.version}</version> + <configuration> + <cleanupDaemonThreads>false</cleanupDaemonThreads> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/src/main/java/com/mongodb/quickstart/AggregationFramework.java b/src/main/java/com/mongodb/quickstart/AggregationFramework.java new file mode 100644 index 0000000..e3c9818 --- /dev/null +++ b/src/main/java/com/mongodb/quickstart/AggregationFramework.java @@ -0,0 +1,72 @@ +package com.mongodb.quickstart; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.bson.json.JsonWriterSettings; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import static com.mongodb.client.model.Accumulators.push; +import static com.mongodb.client.model.Accumulators.sum; +import static com.mongodb.client.model.Aggregates.*; +import static com.mongodb.client.model.Filters.eq; +import static com.mongodb.client.model.Projections.*; +import static com.mongodb.client.model.Sorts.descending; + +public class AggregationFramework { + + public static void main(String[] args) { + String connectionString = System.getProperty("mongodb.uri"); + try (MongoClient mongoClient = MongoClients.create(connectionString)) { + MongoDatabase db = mongoClient.getDatabase("sample_training"); + MongoCollection<Document> zips = db.getCollection("zips"); + MongoCollection<Document> posts = db.getCollection("posts"); + threeMostPopulatedCitiesInTexas(zips); + threeMostPopularTags(posts); + } + } + + /** + * find the 3 most densely populated cities in Texas. + * + * @param zips sample_training.zips collection from the MongoDB Sample Dataset in MongoDB Atlas. + */ + private static void threeMostPopulatedCitiesInTexas(MongoCollection<Document> zips) { + Bson match = match(eq("state", "TX")); + Bson group = group("$city", sum("totalPop", "$pop")); + Bson project = project(fields(excludeId(), include("totalPop"), computed("city", "$_id"))); + Bson sort = sort(descending("totalPop")); + Bson limit = limit(3); + + List<Document> results = zips.aggregate(List.of(match, group, project, sort, limit)).into(new ArrayList<>()); + System.out.println("==> 3 most densely populated cities in Texas"); + results.forEach(printDocuments()); + } + + /** + * find the 3 most popular tags and their post titles + * + * @param posts sample_training.posts collection from the MongoDB Sample Dataset in MongoDB Atlas. + */ + private static void threeMostPopularTags(MongoCollection<Document> posts) { + Bson unwind = unwind("$tags"); + Bson group = group("$tags", sum("count", 1L), push("titles", "$title")); + Bson sort = sort(descending("count")); + Bson limit = limit(3); + Bson project = project(fields(excludeId(), computed("tag", "$_id"), include("count", "titles"))); + + List<Document> results = posts.aggregate(List.of(unwind, group, sort, limit, project)).into(new ArrayList<>()); + System.out.println("==> 3 most popular tags and their posts titles"); + results.forEach(printDocuments()); + } + + private static Consumer<Document> printDocuments() { + return doc -> System.out.println(doc.toJson(JsonWriterSettings.builder().indent(true).build())); + } +} diff --git a/src/main/java/com/mongodb/quickstart/Connection.java b/src/main/java/com/mongodb/quickstart/Connection.java new file mode 100644 index 0000000..4544bd3 --- /dev/null +++ b/src/main/java/com/mongodb/quickstart/Connection.java @@ -0,0 +1,30 @@ +package com.mongodb.quickstart; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import org.bson.Document; +import org.bson.json.JsonWriterSettings; + +import java.util.ArrayList; +import java.util.List; + +public class Connection { + + public static void main(String[] args) { + String connectionString = System.getProperty("mongodb.uri"); + try (MongoClient mongoClient = MongoClients.create(connectionString)) { + System.out.println("=> Connection successful: " + preFlightChecks(mongoClient)); + System.out.println("=> Print list of databases:"); + List<Document> databases = mongoClient.listDatabases().into(new ArrayList<>()); + databases.forEach(db -> System.out.println(db.toJson())); + } + } + + static boolean preFlightChecks(MongoClient mongoClient) { + Document pingCommand = new Document("ping", 1); + Document response = mongoClient.getDatabase("admin").runCommand(pingCommand); + System.out.println("=> Print result of the '{ping: 1}' command."); + System.out.println(response.toJson(JsonWriterSettings.builder().indent(true).build())); + return response.get("ok", Number.class).intValue() == 1; + } +} diff --git a/src/main/java/com/mongodb/quickstart/Create.java b/src/main/java/com/mongodb/quickstart/Create.java new file mode 100644 index 0000000..604ffe4 --- /dev/null +++ b/src/main/java/com/mongodb/quickstart/Create.java @@ -0,0 +1,54 @@ +package com.mongodb.quickstart; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.InsertManyOptions; +import org.bson.Document; +import org.bson.types.ObjectId; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class Create { + + private static final Random rand = new Random(); + + public static void main(String[] args) { + try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { + + MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); + MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); + + insertOneDocument(gradesCollection); + insertManyDocuments(gradesCollection); + } + } + + private static void insertOneDocument(MongoCollection<Document> gradesCollection) { + gradesCollection.insertOne(generateNewGrade(10000d, 1d)); + System.out.println("One grade inserted for studentId 10000."); + } + + private static void insertManyDocuments(MongoCollection<Document> gradesCollection) { + List<Document> grades = new ArrayList<>(); + for (double classId = 1d; classId <= 10d; classId++) { + grades.add(generateNewGrade(10001d, classId)); + } + + gradesCollection.insertMany(grades, new InsertManyOptions().ordered(false)); + System.out.println("Ten grades inserted for studentId 10001."); + } + + private static Document generateNewGrade(double studentId, double classId) { + List<Document> scores = List.of(new Document("type", "exam").append("score", rand.nextDouble() * 100), + new Document("type", "quiz").append("score", rand.nextDouble() * 100), + new Document("type", "homework").append("score", rand.nextDouble() * 100), + new Document("type", "homework").append("score", rand.nextDouble() * 100)); + return new Document("_id", new ObjectId()).append("student_id", studentId) + .append("class_id", classId) + .append("scores", scores); + } +} diff --git a/src/main/java/com/mongodb/quickstart/Delete.java b/src/main/java/com/mongodb/quickstart/Delete.java new file mode 100644 index 0000000..a2a3916 --- /dev/null +++ b/src/main/java/com/mongodb/quickstart/Delete.java @@ -0,0 +1,41 @@ +package com.mongodb.quickstart; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.result.DeleteResult; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.bson.json.JsonWriterSettings; + +import static com.mongodb.client.model.Filters.eq; +import static com.mongodb.client.model.Filters.gte; + +public class Delete { + + public static void main(String[] args) { + try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { + MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); + MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); + + // delete one document + Bson filter = eq("student_id", 10000); + DeleteResult result = gradesCollection.deleteOne(filter); + System.out.println(result); + + // findOneAndDelete operation + filter = eq("student_id", 10002); + Document doc = gradesCollection.findOneAndDelete(filter); + System.out.println(doc.toJson(JsonWriterSettings.builder().indent(true).build())); + + // delete many documents + filter = gte("student_id", 10000); + result = gradesCollection.deleteMany(filter); + System.out.println(result); + + // delete the entire collection and its metadata (indexes, chunk metadata, etc). + gradesCollection.drop(); + } + } +} diff --git a/src/main/java/com/mongodb/quickstart/MappingPOJO.java b/src/main/java/com/mongodb/quickstart/MappingPOJO.java new file mode 100644 index 0000000..37b8773 --- /dev/null +++ b/src/main/java/com/mongodb/quickstart/MappingPOJO.java @@ -0,0 +1,62 @@ +package com.mongodb.quickstart; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.FindOneAndReplaceOptions; +import com.mongodb.client.model.ReturnDocument; +import com.mongodb.quickstart.models.Grade; +import com.mongodb.quickstart.models.Score; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.codecs.pojo.PojoCodecProvider; +import org.bson.conversions.Bson; + +import java.util.ArrayList; +import java.util.List; + +import static com.mongodb.client.model.Filters.eq; +import static org.bson.codecs.configuration.CodecRegistries.fromProviders; +import static org.bson.codecs.configuration.CodecRegistries.fromRegistries; + +public class MappingPOJO { + + public static void main(String[] args) { + ConnectionString connectionString = new ConnectionString(System.getProperty("mongodb.uri")); + CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build()); + CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry); + MongoClientSettings clientSettings = MongoClientSettings.builder() + .applyConnectionString(connectionString) + .codecRegistry(codecRegistry) + .build(); + try (MongoClient mongoClient = MongoClients.create(clientSettings)) { + MongoDatabase db = mongoClient.getDatabase("sample_training"); + MongoCollection<Grade> grades = db.getCollection("grades", Grade.class); + + // create a new grade. + Grade newGrade = new Grade().setStudentId(10003d) + .setClassId(10d) + .setScores(List.of(new Score().setType("homework").setScore(50d))); + grades.insertOne(newGrade); + System.out.println("Grade inserted."); + + // find this grade. + Grade grade = grades.find(eq("student_id", 10003d)).first(); + System.out.println("Grade found:\t" + grade); + + // update this grade: adding an exam grade + List<Score> newScores = new ArrayList<>(grade.getScores()); + newScores.add(new Score().setType("exam").setScore(42d)); + grade.setScores(newScores); + Bson filterByGradeId = eq("_id", grade.getId()); + FindOneAndReplaceOptions returnDocAfterReplace = new FindOneAndReplaceOptions().returnDocument(ReturnDocument.AFTER); + Grade updatedGrade = grades.findOneAndReplace(filterByGradeId, grade, returnDocAfterReplace); + System.out.println("Grade replaced:\t" + updatedGrade); + + // delete this grade + System.out.println("Grade deleted:\t" + grades.deleteOne(filterByGradeId)); + } + } +} diff --git a/src/main/java/com/mongodb/quickstart/Read.java b/src/main/java/com/mongodb/quickstart/Read.java new file mode 100644 index 0000000..6a1200b --- /dev/null +++ b/src/main/java/com/mongodb/quickstart/Read.java @@ -0,0 +1,63 @@ +package com.mongodb.quickstart; + +import com.mongodb.client.*; +import org.bson.Document; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import static com.mongodb.client.model.Filters.*; +import static com.mongodb.client.model.Projections.*; +import static com.mongodb.client.model.Sorts.descending; + +public class Read { + + public static void main(String[] args) { + try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { + MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); + MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); + + // find one document with new Document + Document student1 = gradesCollection.find(new Document("student_id", 10000)).first(); + System.out.println("Student 1: " + student1.toJson()); + + // find one document with Filters.eq() + Document student2 = gradesCollection.find(eq("student_id", 10000)).first(); + System.out.println("Student 2: " + student2.toJson()); + + // find a list of documents and iterate throw it using an iterator. + FindIterable<Document> iterable = gradesCollection.find(gte("student_id", 10000)); + MongoCursor<Document> cursor = iterable.iterator(); + System.out.println("Student list with a cursor: "); + while (cursor.hasNext()) { + System.out.println(cursor.next().toJson()); + } + + // find a list of documents and use a List object instead of an iterator + List<Document> studentList = gradesCollection.find(gte("student_id", 10000)).into(new ArrayList<>()); + System.out.println("Student list with an ArrayList:"); + for (Document student : studentList) { + System.out.println(student.toJson()); + } + + // find a list of documents and print using a consumer + System.out.println("Student list using a Consumer:"); + Consumer<Document> printConsumer = document -> System.out.println(document.toJson()); + gradesCollection.find(gte("student_id", 10000)).forEach(printConsumer); + + // find a list of documents with sort, skip, limit and projection + List<Document> docs = gradesCollection.find(and(eq("student_id", 10001), lte("class_id", 5))) + .projection(fields(excludeId(), include("class_id", "student_id"))) + .sort(descending("class_id")) + .skip(2) + .limit(2) + .into(new ArrayList<>()); + + System.out.println("Student sorted, skipped, limited and projected:"); + for (Document student : docs) { + System.out.println(student.toJson()); + } + } + } +} diff --git a/src/main/java/com/mongodb/quickstart/Update.java b/src/main/java/com/mongodb/quickstart/Update.java new file mode 100644 index 0000000..0aa4963 --- /dev/null +++ b/src/main/java/com/mongodb/quickstart/Update.java @@ -0,0 +1,72 @@ +package com.mongodb.quickstart; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.FindOneAndUpdateOptions; +import com.mongodb.client.model.ReturnDocument; +import com.mongodb.client.model.UpdateOptions; +import com.mongodb.client.result.UpdateResult; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.bson.json.JsonWriterSettings; + +import static com.mongodb.client.model.Filters.and; +import static com.mongodb.client.model.Filters.eq; +import static com.mongodb.client.model.Updates.*; + +public class Update { + + public static void main(String[] args) { + JsonWriterSettings prettyPrint = JsonWriterSettings.builder().indent(true).build(); + + try (MongoClient mongoClient = MongoClients.create(System.getProperty("mongodb.uri"))) { + MongoDatabase sampleTrainingDB = mongoClient.getDatabase("sample_training"); + MongoCollection<Document> gradesCollection = sampleTrainingDB.getCollection("grades"); + + // update one document + Bson filter = eq("student_id", 10000); + Bson updateOperation = set("comment", "You should learn MongoDB!"); + UpdateResult updateResult = gradesCollection.updateOne(filter, updateOperation); + System.out.println("=> Updating the doc with {\"student_id\":10000}. Adding comment."); + System.out.println(gradesCollection.find(filter).first().toJson(prettyPrint)); + System.out.println(updateResult); + + // upsert + filter = and(eq("student_id", 10002d), eq("class_id", 10d)); + updateOperation = push("comments", "You will learn a lot if you read the MongoDB blog!"); + UpdateOptions options = new UpdateOptions().upsert(true); + updateResult = gradesCollection.updateOne(filter, updateOperation, options); + System.out.println("\n=> Upsert document with {\"student_id\":10002.0, \"class_id\": 10.0} because it doesn't exist yet."); + System.out.println(updateResult); + System.out.println(gradesCollection.find(filter).first().toJson(prettyPrint)); + + // update many documents + filter = eq("student_id", 10001); + updateResult = gradesCollection.updateMany(filter, updateOperation); + System.out.println("\n=> Updating all the documents with {\"student_id\":10001}."); + System.out.println(updateResult); + + // findOneAndUpdate + filter = eq("student_id", 10000); + Bson update1 = inc("x", 10); // increment x by 10. As x doesn't exist yet, x=10. + Bson update2 = rename("class_id", "new_class_id"); // rename variable "class_id" in "new_class_id". + Bson update3 = mul("scores.0.score", 2); // multiply the first score in the array by 2. + Bson update4 = addToSet("comments", "This comment is uniq"); // creating an array with a comment. + Bson update5 = addToSet("comments", "This comment is uniq"); // using addToSet so no effect. + Bson updates = combine(update1, update2, update3, update4, update5); + // returns the old version of the document before the update. + Document oldVersion = gradesCollection.findOneAndUpdate(filter, updates); + System.out.println("\n=> FindOneAndUpdate operation. Printing the old version by default:"); + System.out.println(oldVersion.toJson(prettyPrint)); + + // but I can also request the new version + filter = eq("student_id", 10001); + FindOneAndUpdateOptions optionAfter = new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER); + Document newVersion = gradesCollection.findOneAndUpdate(filter, updates, optionAfter); + System.out.println("\n=> FindOneAndUpdate operation. But we can also ask for the new version of the doc:"); + System.out.println(newVersion.toJson(prettyPrint)); + } + } +} diff --git a/src/main/java/com/mongodb/quickstart/models/Grade.java b/src/main/java/com/mongodb/quickstart/models/Grade.java new file mode 100644 index 0000000..2a2a994 --- /dev/null +++ b/src/main/java/com/mongodb/quickstart/models/Grade.java @@ -0,0 +1,81 @@ +package com.mongodb.quickstart.models; + +import org.bson.codecs.pojo.annotations.BsonProperty; +import org.bson.types.ObjectId; + +import java.util.List; +import java.util.Objects; + +public class Grade { + + private ObjectId id; + @BsonProperty(value = "student_id") + private Double studentId; + @BsonProperty(value = "class_id") + private Double classId; + private List<Score> scores; + + public ObjectId getId() { + return id; + } + + public Grade setId(ObjectId id) { + this.id = id; + return this; + } + + public Double getStudentId() { + return studentId; + } + + public Grade setStudentId(Double studentId) { + this.studentId = studentId; + return this; + } + + public Double getClassId() { + return classId; + } + + public Grade setClassId(Double classId) { + this.classId = classId; + return this; + } + + public List<Score> getScores() { + return scores; + } + + public Grade setScores(List<Score> scores) { + this.scores = scores; + return this; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("Grade{"); + sb.append("id=").append(id); + sb.append(", student_id=").append(studentId); + sb.append(", class_id=").append(classId); + sb.append(", scores=").append(scores); + sb.append('}'); + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Grade grade = (Grade) o; + return Objects.equals(id, grade.id) && Objects.equals(studentId, grade.studentId) && Objects.equals(classId, + grade.classId) && Objects + .equals(scores, grade.scores); + } + + @Override + public int hashCode() { + return Objects.hash(id, studentId, classId, scores); + } +} diff --git a/src/main/java/com/mongodb/quickstart/models/Score.java b/src/main/java/com/mongodb/quickstart/models/Score.java new file mode 100644 index 0000000..d1ef735 --- /dev/null +++ b/src/main/java/com/mongodb/quickstart/models/Score.java @@ -0,0 +1,51 @@ +package com.mongodb.quickstart.models; + +import java.util.Objects; + +public class Score { + + private String type; + private Double score; + + public String getType() { + return type; + } + + public Score setType(String type) { + this.type = type; + return this; + } + + public Double getScore() { + return score; + } + + public Score setScore(Double score) { + this.score = score; + return this; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("Score{"); + sb.append("type='").append(type).append('\''); + sb.append(", score=").append(score); + sb.append('}'); + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Score score1 = (Score) o; + return Objects.equals(type, score1.type) && Objects.equals(score, score1.score); + } + + @Override + public int hashCode() { + return Objects.hash(type, score); + } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..0aea751 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,10 @@ +<configuration> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + <root level="warn"> + <appender-ref ref="STDOUT" /> + </root> +</configuration> -- GitLab