杰瑞科技汇

Java MongoDB教程怎么学?入门到实战指南

Java MongoDB 全栈教程:从入门到精通

本教程将引导你一步步学习如何使用 Java 驱动程序与 MongoDB 进行交互,我们将涵盖安装、连接、基本 CRUD(创建、读取、更新、删除)操作、聚合以及一些高级主题。

Java MongoDB教程怎么学?入门到实战指南-图1
(图片来源网络,侵删)

目录

  1. 准备工作
    • 安装 MongoDB
    • 安装 Java 和 Maven
  2. 创建第一个 Java 项目

    使用 Maven 引入 MongoDB 驱动

  3. 连接到 MongoDB
    • MongoClientMongoDatabase
    • 连接字符串
  4. 核心概念:集合与文档
    • 什么是集合?
    • 什么是文档?
    • 使用 MongoCollection
  5. CRUD 操作详解
    • Create: 插入文档 (insertOne, insertMany)
    • Read: 查询文档 (find, findOne)
    • Update: 更新文档 (updateOne, updateMany)
    • Delete: 删除文档 (deleteOne, deleteMany)
  6. 高级查询与聚合
    • 使用 Filters 进行复杂查询
    • 使用 Projections 选择返回字段
    • 使用 SortLimit 排序和限制结果
    • 聚合管道简介 (Aggregates)
  7. 处理文档与 JSON
    • Document
    • 使用 POJO (Plain Old Java Object)
  8. 索引
    • 创建索引
    • 查看索引
  9. 实战示例:一个简单的待办事项应用
  10. 总结与最佳实践

准备工作

在开始之前,请确保你的开发环境已经准备好。

a. 安装 MongoDB

如果你还没有安装 MongoDB,请按照官方指南进行安装:

安装完成后,启动 MongoDB 服务,默认情况下,它会在 localhost:27017 上运行。

b. 安装 Java 和 Maven

你需要安装 Java Development Kit (JDK) 8 或更高版本,以及 Apache Maven。

确保 javamvn 命令可以在你的终端/命令行中使用。

创建第一个 Java 项目

我们将使用 Maven 来管理项目依赖。

  1. 在你选择的目录下,打开终端。

  2. 运行以下 Maven 命令来创建一个快速原型项目:

    mvn archetype:generate -DgroupId=com.example -DartifactId=mongodb-java-tutorial -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
  3. 进入项目目录:

    cd mongodb-java-tutorial
  4. 打开 pom.xml 文件,添加 MongoDB Java 驱动的依赖,我们使用最新的稳定版本(请务必检查官网获取最新版本)。

    <dependencies>
        <!-- MongoDB Java Driver -->
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver-sync</artifactId>
            <version>4.11.1</version> <!-- 请替换为最新版本 -->
        </dependency>
        <!-- JUnit for testing (可选) -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
  5. 你可以使用你的 IDE(如 IntelliJ IDEA 或 Eclipse)打开这个项目,或者直接在命令行中使用 mvn compile 来编译项目。

连接到 MongoDB

连接是所有操作的第一步,MongoDB Java 驱动提供了非常简洁的 API。

创建一个新的 Java 类 MongoDBConnection.java

package com.example;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
public class MongoDBConnection {
    public static void main(String[] args) {
        // 1. 定义连接字符串
        // 默认连接到本地MongoDB,默认端口27017
        String connectionString = "mongodb://localhost:27017";
        // 2. 创建一个 MongoClient 实例
        // MongoClient 是线程安全的,推荐在整个应用中只创建一个实例
        try (MongoClient mongoClient = MongoClients.create(connectionString)) {
            // 3. 获取数据库
            // 如果数据库不存在,MongoDB 会在第一次插入数据时自动创建它
            MongoDatabase database = mongoClient.getDatabase("myTestDB");
            System.out.println("成功连接到数据库: " + database.getName());
            // 你可以在这里进行后续操作...
            // 获取一个集合
            // database.getCollection("users");
        } catch (Exception e) {
            System.err.println("连接 MongoDB 时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

代码解释:

  • MongoClients.create(connectionString): 这是创建连接的入口点,连接字符串 mongodb://host:port 指定了 MongoDB 服务器的地址。
  • mongoClient.getDatabase("myTestDB"): 获取一个数据库对象,如果数据库不存在,MongoDB 不会立即创建它,而是在你第一次向该数据库中的集合写入数据时创建。
  • try-with-resources: MongoClient 实现了 AutoCloseable,使用 try-with-resources 语句可以确保它在代码块执行完毕后自动关闭,防止资源泄漏。

核心概念:集合与文档

在 MongoDB 中,数据以 BSON (Binary JSON) 格式存储,类似于 JSON。

  • 文档: 数据的基本单位,是一个键值对集合。{ "name": "Alice", "age": 30 }
  • 集合: 文档的组,类似于关系型数据库中的表,集合中的文档结构可以不同(这是 MongoDB 的一个特点)。

在 Java 驱动中,我们使用 MongoCollection 来操作集合。

// 在连接代码之后
// 获取一个名为 "users" 的集合
// 如果集合不存在,在第一次插入文档时也会自动创建
com.mongodb.client.MongoCollection<org.bson.Document> collection = database.getCollection("users");

CRUD 操作详解

这是 MongoDB 操作的核心,我们将使用 MongoCollection<Document> 来进行演示。

C - Create (插入)

插入单个文档 (insertOne)
// 创建一个文档
Document doc = new Document("name", "John Doe")
                 .append("age", 30)
                 .append("email", "john.doe@example.com");
// 插入文档
collection.insertOne(doc);
System.out.println("文档已插入");
插入多个文档 (insertMany)
List<Document> documents = new ArrayList<>();
documents.add(new Document("name", "Alice").append("age", 25));
documents.add(new Document("name", "Bob").append("age", 35));
collection.insertMany(documents);
System.out.println("多个文档已插入");

R - Read (查询)

查找所有文档 (find)

find() 方法返回一个 FindIterable<Document>,你需要遍历它来获取结果。

// 查找集合中的所有文档
System.out.println("----- 查找所有用户 -----");
collection.find().forEach(doc -> System.out.println(doc.toJson()));
按条件查询 (find + Filters)

使用 Filters 类来构建查询条件,这是推荐的方式。

import static com.mongodb.client.model.Filters.*;
// 查找 name 为 "Alice" 的用户
System.out.println("----- 查找名为 Alice 的用户 -----");
collection.find(eq("name", "Alice")).forEach(doc -> System.out.println(doc.toJson()));
// 查找 age 大于 30 的用户
System.out.println("----- 查找年龄大于 30 的用户 -----");
collection.find(gt("age", 30)).forEach(doc -> System.out.println(doc.toJson()));
// 组合查询:查找 age 大于 30 且 name 为 "Bob" 的用户
System.out.println("----- 查找年龄大于 30 且名为 Bob 的用户 -----");
collection.find(and(gt("age", 30), eq("name", "Bob"))).forEach(doc -> System.out.println(doc.toJson()));

U - Update (更新)

更新单个文档 (updateOne)

更新 name 为 "Alice" 的用户,将其年龄设置为 26。

// 更新条件
Document query = new Document("name", "Alice");
// 更新操作
Document update = new Document("$set", new Document("age", 26));
// 执行更新
UpdateResult result = collection.updateOne(query, update);
System.out.println("匹配的文档数: " + result.getMatchedCount());
System.out.println("修改的文档数: " + result.getModifiedCount());
更新多个文档 (updateMany)

将所有年龄小于 30 的用户的 status 字段设置为 "young"。

// 更新条件
Document query = new Document("age", lt(30));
// 更新操作
Document update = new Document("$set", new Document("status", "young"));
// 执行更新
UpdateResult result = collection.updateMany(query, update);
System.out.println("匹配的文档数: " + result.getMatchedCount());
System.out.println("修改的文档数: " + result.getModifiedCount());

D - Delete (删除)

删除单个文档 (deleteOne)

删除 name 为 "John Doe" 的用户。

// 删除条件
Document query = new Document("name", "John Doe");
// 执行删除
DeleteResult result = collection.deleteOne(query);
System.out.println("删除的文档数: " + result.getDeletedCount());
删除多个文档 (deleteMany)

删除所有 status 为 "young" 的用户。

// 删除条件
Document query = new Document("status", "young");
// 执行删除
DeleteResult result = collection.deleteMany(query);
System.out.println("删除的文档数: " + result.getDeletedCount());

高级查询与聚合

使用 Projections 选择字段

默认情况下,find() 会返回文档的所有字段,你可以使用 Projections 来指定只返回需要的字段。

import static com.mongodb.client.model.Projections.*;
// 只返回 name 和 age 字段,不返回 _id
System.out.println("----- 只查询 name 和 age -----");
collection.find().projection(fields(include("name", "age"), excludeId()))
                .forEach(doc -> System.out.println(doc.toJson()));

使用 SortLimit

import static com.mongodb.client.model.Sorts.*;
// 按 age 降序排序,并只返回前 2 个结果
System.out.println("----- 按年龄降序排序并限制结果 -----");
collection.find().sort(descending("age")).limit(2)
                .forEach(doc -> System.out.println(doc.toJson()));

聚合管道 (Aggregates)

聚合是 MongoDB 中最强大的功能之一,它允许你对数据进行复杂的处理,如分组、计算、过滤等。

示例:按年龄分组并计算每个年龄的人数

import static com.mongodb.client.model.Aggregates.*;
List<Document> pipeline = Arrays.asList(
    // 第一阶段:按 "age" 字段分组
    group("$age", Accumulators.sum("count", 1)),
    // 第二阶段:按 "count" 降序排序
    sort(descending("count"))
);
// 执行聚合
collection.aggregate(pipeline).forEach(doc -> System.out.println(doc.toJson()));

处理文档与 JSON

到目前为止,我们一直在使用 org.bson.Document 类来表示文档,它非常灵活,但有时我们更希望使用强类型的 Java 对象(POJO)。

使用 POJO

  1. 创建一个 Java 类,其字段名与 BSON 文档的键名相匹配,你可以使用 @BsonProperty 注解来处理名称不匹配的情况。

    package com.example;
    import org.bson.types.ObjectId;
    import org.bson.codecs.pojo.annotations.BsonId;
    import org.bson.codecs.pojo.annotations.BsonProperty;
    public class User {
        @BsonId // 标记此字段对应文档的 _id
        private ObjectId id;
        @BsonProperty("full_name") // 映射到 BSON 中的 "full_name" 字段
        private String name;
        private int age;
        // 无参构造函数是必需的
        public User() {}
        // getter 和 setter 方法
        public ObjectId getId() { return id; }
        public void setId(ObjectId id) { this.id = id; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public int getAge() { return age; }
        public void setAge(int age) { this.age = age; }
        @Override
        public String toString() {
            return "User{" +
                   "id=" + id +
                   ", name='" + name + '\'' +
                   ", age=" + age +
                   '}';
        }
    }
  2. 修改你的 MongoCollection 以使用这个 POJO 类型。

    // 在连接数据库后
    MongoCollection<User> userCollection = database.getCollection("users_pojos", User.class);
    // 插入 POJO
    User newUser = new User();
    newUser.setName("Charlie Brown");
    newUser.setAge(8);
    userCollection.insertOne(newUser);
    System.out.println("已插入 POJO: " + newUser);
    // 查询并获取 POJO
    userCollection.find(eq("name", "Charlie Brown")).forEach(user -> {
        System.out.println("查询到的 POJO: " + user);
        System.out.println("ID: " + user.getId()); // _id 会自动映射
    });

    注意: 要使用 POJO,你的 MongoCollection 的泛型类型必须是你的 POJO 类,并且需要确保你的项目中包含了 Jackson 或类似的库(驱动通常会自动处理)。User.class 的存在告诉驱动如何将 BSON 反序列化为 User 对象。

索引

索引用于加速查询,如果没有索引,MongoDB 必须扫描集合中的所有文档(即全表扫描)。

创建索引

name 字段创建一个升序索引。

// 为 "name" 字段创建索引
collection.createIndex(new Document("name", 1)); // 1 表示升序, -1 表示降序
System.out.println("索引已创建");

查看集合的索引

// 获取集合的所有索引信息
collection.listIndexes().forEach(index -> System.out.println(index.toJson()));

实战示例:一个简单的待办事项应用

让我们整合所学知识,创建一个简单的 To-Do List 应用。

TodoApp.java

package com.example;
import com.mongodb.client.*;
import com.mongodb.client.model.*;
import org.bson.Document;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.mongodb.client.model.Filters.*;
import static com.mongodb.client.model.Sorts.*;
public class TodoApp {
    private static final String DB_NAME = "todoDB";
    private static final String COLLECTION_NAME = "tasks";
    private static MongoCollection<Document> collection;
    public static void main(String[] args) {
        // 1. 连接
        try (MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017")) {
            MongoDatabase database = mongoClient.getDatabase(DB_NAME);
            collection = database.getCollection(COLLECTION_NAME);
            System.out.println("成功连接到 " + DB_NAME);
            // 2. 初始化一些数据 (可选)
            initializeData();
            // 3. 执行 CRUD 操作
            System.out.println("\n--- 所有任务 ---");
            findAllTasks();
            System.out.println("\n--- 添加新任务 ---");
            addTask("学习 Java MongoDB", false);
            addTask("去健身房", true);
            System.out.println("\n--- 更新任务状态 ---");
            markTaskAsCompleted("学习 Java MongoDB");
            System.out.println("\n--- 查找所有未完成的任务 ---");
            findIncompleteTasks();
            System.out.println("\n--- 删除已完成的任务 ---");
            deleteCompletedTasks();
            System.out.println("\n--- 最终所有任务 ---");
            findAllTasks();
        }
    }
    private static void initializeData() {
        // 清空旧数据,以便每次运行都干净
        collection.deleteMany(new Document());
        List<Document> initialTasks = Arrays.asList(
            new Document("title", "完成项目报告").append("completed", false),
            new Document("title", "购买杂货").append("completed", true)
        );
        collection.insertMany(initialTasks);
        System.out.println("初始化数据完成。");
    }
    private static void findAllTasks() {
        collection.find().sort(ascending("title")).forEach(doc -> System.out.println(doc.toJson()));
    }
    private static void addTask(String title, boolean completed) {
        Document task = new Document("title", title).append("completed", completed);
        collection.insertOne(task);
        System.out.println("已添加任务: " + title);
    }
    private static void markTaskAsCompleted(String title) {
        UpdateResult result = collection.updateOne(eq("title", title), new Document("$set", new Document("completed", true)));
        if (result.getMatchedCount() > 0) {
            System.out.println("任务 '" + title + "' 已标记为完成。");
        } else {
            System.out.println("未找到任务: " + title);
        }
    }
    private static void findIncompleteTasks() {
        collection.find(eq("completed", false)).forEach(doc -> System.out.println(doc.toJson()));
    }
    private static void deleteCompletedTasks() {
        DeleteResult result = collection.deleteMany(eq("completed", true));
        System.out.println("已删除 " + result.getDeletedCount() + " 个已完成的任务。");
    }
}

总结与最佳实践

  • 连接管理: MongoClient 是重量级且线程安全的,在你的应用中只创建一个实例,并在应用关闭时关闭它。
  • 异常处理: 总是使用 try-catch 块来处理 MongoException 及其子类,例如网络问题、查询错误等。
  • 使用 FiltersProjections: 使用驱动提供的 Filters, Projections, Sorts, Aggregates 等工具类,而不是手动构建 Document 查询,这更安全、更易读。
  • POJO vs. Document: 对于结构固定的数据,优先使用 POJO,它提供了类型安全和更好的 IDE 支持,对于动态或模式不固定的数据,Document 更灵活。
  • 索引: 对于频繁查询的字段,务必创建索引,但要注意,索引会占用存储空间并降低写入速度,因此要权衡使用。
  • 版本兼容性: 确保你的 MongoDB Java 驱动版本与你的 MongoDB 服务器版本兼容,可以参考 MongoDB 驱动兼容性矩阵

希望这份详细的教程能帮助你顺利掌握 Java 与 MongoDB 的开发!

分享:
扫描分享到社交APP
上一篇
下一篇