# MongoDB Java 教程

原文：http://zetcode.com/java/mongodb/

在本教程中，我们将展示如何在 Java 中使用 MongoDB。 在 ZetCode 上有一个简洁的 [Java 教程](/lang/java/)。

MongoDB 是 NoSQL 跨平台的面向文档的数据库。 它是可用的最受欢迎的数据库之一。 MongoDB 由 MongoDB Inc. 开发，并作为免费和开源软件发布。

MongoDB 中的记录是一个文档，它是由字段和值对组成的数据结构。 MongoDB 文档与 JSON 对象相似。 字段的值可以包括其他文档，数组和文档数组。 MongoDB 将文档存储在集合中。 集合类似于关系数据库中的表以及行中的文档。

## 安装 MongoDB

以下命令可用于在基于 Debian 的 Linux 上安装 MongoDB。

```java
$ sudo apt-get install mongodb

```

该命令将安装 MongoDB 随附的必要软件包。

```java
$ sudo service mongodb status
mongodb start/running, process 975

```

使用`sudo service mongodb status`命令，我们检查`mongodb`服务器的状态。

```java
$ sudo service mongodb start
mongodb start/running, process 6448

```

`mongodb`服务器由`sudo service mongodb start`命令启动。

## 建立数据库

`mongo`工具是 MongoDB 的交互式 JavaScript Shell 界面，它为系统管理员提供了一个界面，并为开发人员提供了一种直接测试数据库查询和操作的方法。

```java
$ mongo testdb
MongoDB shell version v4.0.7
connecting to: mongodb://127.0.0.1:27017/testdb?gssapiServiceName=mongodb
...
> db
testdb
> db.cars.insert({name: "Audi", price: 52642})
> db.cars.insert({name: "Mercedes", price: 57127})
> db.cars.insert({name: "Skoda", price: 9000})
> db.cars.insert({name: "Volvo", price: 29000})
> db.cars.insert({name: "Bentley", price: 350000})
> db.cars.insert({name: "Citroen", price: 21000})
> db.cars.insert({name: "Hummer", price: 41400})
> db.cars.insert({name: "Volkswagen", price: 21600})

```

我们创建一个`testdb`数据库，并在`cars`集合中插入八个文档。

## Java MongoDB 驱动程序

我们使用以下 Maven 声明在项目中包括 MongoDB Java 驱动程序。

```java
<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongo-java-driver</artifactId>
    <version>x.y.z</version>
</dependency>

```

它是一个多功能的 JAR，它嵌入了核心驱动程序和 BSON。 BSON 是 Binaryary JSON 的缩写，是类似于 JSON 的文档的二进制编码的序列化。

## Java MongoDB 列出数据库集合

第一个示例连接到`testdb`数据库并检索其集合。

`pom.xml`

```java
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         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.zetcode</groupId>
    <artifactId>mongocommand</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongo-java-driver</artifactId>
            <version>3.10.2</version>
        </dependency>
    </dependencies>

</project>

```

这是我们的`pom.xml`文件。

`com/zetcode/MongoListCollections.java`

```java
package com.zetcode;

import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;

import java.util.logging.Level;
import java.util.logging.Logger;

public class MongoListCollections {

    public static void main(String[] args) {

        Logger mongoLogger = Logger.getLogger("org.mongodb.driver");
        mongoLogger.setLevel(Level.SEVERE);

        try (var mongoClient = MongoClients.create("mongodb://localhost:27017")) {

            MongoDatabase database = mongoClient.getDatabase("testdb");

            for (String name : database.listCollectionNames()) {

                System.out.println(name);
            }
        }
    }
}

```

该示例连接到`testdb`数据库并检索其所有集合。

```java
Logger mongoLogger = Logger.getLogger("org.mongodb.driver");
mongoLogger.setLevel(Level.SEVERE);

```

我们为 MongoDB 设置日志记录级别。 我们仅显示严重错误消息。

```java
try (var mongoClient = MongoClients.create("mongodb://localhost:27017")) {

```

`MongoClient`类用于连接到 MongoDB 服务器。 它是通过`MongoClients.create()`方法调用创建的。 27017 是 MongoDB 服务器监听的默认端口。

```java
MongoDatabase database = mongoClient.getDatabase("testdb");

```

使用`getDatabase()`方法，我们检索了`testdb`数据库。

```java
for (String name : database.listCollectionNames()) {

    System.out.println(name);
}

```

`listCollectionNames()`方法在`testdb`数据库中找到所有集合。

```java
cars
cities

```

在我们的数据库中，我们有这两个集合。

## Java MongoDB 数据库统计

下一个示例连接到`testdb`数据库并获取其统计信息。

`com/zetcode/MongoCommand.java`

```java
package com.zetcode;

import com.mongodb.client.MongoClients;
import org.bson.Document;

import java.util.Map;

public class MongoCommand {

    public static void main(String[] args) {

        try (var mongoClient = MongoClients.create("mongodb://localhost:27017")) {

            var database = mongoClient.getDatabase("testdb");

            var stats = database.runCommand(new Document("dbstats", 1));

            for (Map.Entry<String, Object> set : stats.entrySet()) {

                System.out.format("%s: %s%n", set.getKey(), set.getValue());
            }
        }
    }
}

```

该示例连接到`testdb`数据库并执行`dbstats`命令。 它显示了一些数据库统计信息。

```java
var stats = database.runCommand(new Document("dbstats", 1));

```

使用`runCommand()`方法，执行`dbstats`命令。 该命令返回`Document`，它表示 MongoDB 文档作为映射。

```java
for (Map.Entry<String, Object> set : stats.entrySet()) {

    System.out.format("%s: %s%n", set.getKey(), set.getValue());
}

```

我们遍历文档的条目。

```java
db: testdb
collections: 2
views: 0
objects: 9
avgObjSize: 48.111111111111114
dataSize: 433.0
storageSize: 57344.0
numExtents: 0
indexes: 2
indexSize: 57344.0
fsUsedSize: 1.4818904064E11
fsTotalSize: 2.547211264E11
ok: 1.0

```

这是一个示例输出。

## Java MongoDB 读取数据

`MongoCollection`用于存储从集合返回的 mongo 文档。 `MongoCursor`是一个游标，用于遍历数据库查询的结果。 确保在发生异常时将其关闭。

`com/zetcode/MongoReadAll.java`

```java
package com.zetcode;

import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import org.bson.Document;

import java.util.ArrayList;

public class MongoReadAll {

    public static void main(String[] args) {

        try (var mongoClient = MongoClients.create("mongodb://localhost:27017")) {

            var database = mongoClient.getDatabase("testdb");

            MongoCollection<Document> collection = database.getCollection("cars");

            try (MongoCursor<Document> cur = collection.find().iterator()) {

                while (cur.hasNext()) {

                    var doc = cur.next();
                    var cars = new ArrayList<>(doc.values());

                    System.out.printf("%s: %s%n", cars.get(1), cars.get(2));
                }
            }
        }
    }
}

```

在示例中，我们遍历`cars`集合的所有数据。

```java
MongoCollection<Document> collection = database.getCollection("cars");

```

我们使用`getCollection()`方法检索`cars`集合。

```java
try (MongoCursor<Document> cur = collection.find().iterator()) {

    while (cur.hasNext()) {

        var doc = cur.next();
        var cars = new ArrayList<>(doc.values());

        System.out.printf("%s: %s%n", cars.get(1), cars.get(2));
    }
}

```

我们遍历集合的文档。 `find()`方法查找集合中的所有文档。

```java
Audi: 52642.0
Mercedes: 57127.0
Skoda: 9000.0
Volvo: 29000.0
Bentley: 350000.0
Citroen: 21000.0
Hummer: 41400.0
Volkswagen: 21600.0

```

这是示例的输出。

## Java MongoDB 查询运算符

可以使用 MongoDB 查询运算符（例如`$gt`，`$lt`或`$ne`）过滤数据。 可以在`BasicDBObject`类中指定查询运算符。

`com/zetcode/MongoReadGreaterThan.java`

```java
package com.zetcode;

import com.mongodb.BasicDBObject;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import org.bson.Document;

import java.util.function.Consumer;

public class MongoReadGreaterThan {

    public static void main(String[] args) {

        try (var mongoClient = MongoClients.create("mongodb://localhost:27017")) {

            var database = mongoClient.getDatabase("testdb");

            MongoCollection<Document> collection = database.getCollection("cars");

            var query = new BasicDBObject("price",
                    new BasicDBObject("$gt", 30000));

            collection.find(query).forEach((Consumer<Document>) doc ->
                     System.out.println(doc.toJson()));
        }
    }
}

```

该示例打印汽车价格大于 30,000 的所有文档。

```java
var query = new BasicDBObject("price",
    new BasicDBObject("$gt", 30000));

```

我们使用`$gt`查询运算符。

```java
collection.find(query).forEach((Consumer<Document>) doc ->
    System.out.println(doc.toJson()));

```

`forEach()`方法是一种语法糖，可以避免应用代码担心不必手动关闭游标。 使用`toJson()`方法以 JSON 格式打印数据。

```java
{"_id": {"$oid": "5d4d13d6463315268eb7376b"}, "name": "Audi", "price": 52642.0}
{"_id": {"$oid": "5d4d13f5463315268eb7376c"}, "name": "Mercedes", "price": 57127.0}
{"_id": {"$oid": "5d4d140d463315268eb7376f"}, "name": "Bentley", "price": 350000.0}
{"_id": {"$oid": "5d4d1415463315268eb73771"}, "name": "Hummer", "price": 41400.0}

```

这是 JSON 格式的示例输出。 仅包括价格超过 30,000 的汽车。

## Java MongoDB 工厂过滤器查询方法

Java MongoDB 驱动程序包含查询过滤器的工厂方法。

`com/zetcode/MongoFilter.java`

```java
package com.zetcode;

import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

import java.util.ArrayList;

import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.gt;
import static com.mongodb.client.model.Filters.lt;

public class MongoFilter {

    public static void main(String[] args) {

        try (var mongoClient = MongoClients.create("mongodb://localhost:27017")) {

            var database = mongoClient.getDatabase("testdb");

            MongoCollection<Document> collection = database.getCollection("cars");

            FindIterable fit = collection.find(and(lt("price", 50000),
                    gt("price", 20000))).sort(new Document("price", -1));

            var docs = new ArrayList<Document>();

            fit.into(docs);

            for (Document doc : docs) {

                System.out.println(doc);
            }
        }
    }
}

```

在示例中，我们检索价格在 20,000 到 50,000 之间的汽车。

```java
FindIterable fit = collection.find(and(lt("price", 50000),
    gt("price", 20000))).sort(new Document("price", -1));

```

`and()`，`gt()`和`lt()`是工厂过滤方法。 此外，数据使用`sort()`方法排序。

```java
Document{{_id=5d4d1415463315268eb73771, name=Hummer, price=41400.0}}
Document{{_id=5d4d1408463315268eb7376e, name=Volvo, price=29000.0}}
Document{{_id=5d4d1419463315268eb73772, name=Volkswagen, price=21600.0}}
Document{{_id=5d4d1411463315268eb73770, name=Citroen, price=21000.0}}

```

This is the output of the example.

## Java MongoDB 投影

`Projections`类为所有 MongoDB 投影运算符提供了静态工厂方法。 默认情况下，将投影每个文档的所有字段。 我们可以使用`include`和`exclude()`方法来确定应将哪些字段投影到我们的输出中。

`com/zetcode/MongoProjection.java`

```java
package com.zetcode;

import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import org.bson.Document;

import java.util.ArrayList;

import static com.mongodb.client.model.Projections.excludeId;

public class MongoProjection {

    public static void main(String[] args) {

        try (var mongoClient = MongoClients.create("mongodb://localhost:27017")) {

            var database = mongoClient.getDatabase("testdb");

            MongoCollection<Document> collection = database.getCollection("cars");

            FindIterable it = collection.find().projection(excludeId());

            var docs = new ArrayList<Document>();

            it.into(docs);

            for (Document doc : docs) {

                System.out.println(doc);
            }
        }
    }
}

```

该示例从输出中排除`_id`字段。

```java
FindIterable it = collection.find().projection(excludeId());

```

`projection()`方法设置一个文档，该文档描述要为所有匹配的文档返回的字段。 `excludeId()`是`exclude("_id")`的同义词。

```java
Document{{name=Audi, price=52642.0}}
Document{{name=Mercedes, price=57127.0}}
Document{{name=Skoda, price=9000.0}}
Document{{name=Volvo, price=29000.0}}
Document{{name=Bentley, price=350000.0}}
Document{{name=Citroen, price=21000.0}}
Document{{name=Hummer, price=41400.0}}
Document{{name=Volkswagen, price=21600.0}}

```

这是示例的输出。

## Java MongoDB 限制数据输出

`limit`查询选项指定要返回的文档数量，`skip()`选项指定某些文档。

`com/zetcode/MongoSkipLimit.java`

```java
package com.zetcode;

import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import org.bson.Document;

import java.util.function.Consumer;

public class MongoSkipLimit {

    public static void main(String[] args) {

        try (var mongoClient = MongoClients.create("mongodb://localhost:27017")) {

            var database = mongoClient.getDatabase("testdb");

            MongoCollection<Document> collection = database.getCollection("cars");
            FindIterable<Document> fit = collection.find().skip(2).limit(5);

            fit.forEach((Consumer<Document>) System.out::println);
        }
    }
}

```

该示例从`testdb.cars`集合中读取，跳过前两个文档，并将输出限制为五个文档。

```java
FindIterable<Document> fit = collection.find().skip(2).limit(5);

```

`FindIterable`的`skip()`方法跳过前两个文档，`limit()`方法将输出限制为五个文档。

```java
fit.forEach((Consumer<Document>) System.out::println);

```

在这里，我们使用 Java8 构造来打印文档。

```java
Document{{_id=5d4d13fb463315268eb7376d, name=Skoda, price=9000.0}}
Document{{_id=5d4d1408463315268eb7376e, name=Volvo, price=29000.0}}
Document{{_id=5d4d140d463315268eb7376f, name=Bentley, price=350000.0}}
Document{{_id=5d4d1411463315268eb73770, name=Citroen, price=21000.0}}
Document{{_id=5d4d1415463315268eb73771, name=Hummer, price=41400.0}}

```

This is the output of the example.

## Java MongoDB 创建集合

`MongoDatabase`的`createCollection()`方法在数据库中创建一个新集合。 `MongoCollection`的`insertMany()`方法将一个或多个文档插入到集合中。

`com/zetcode/MongoCreateCollection.java`

```java
package com.zetcode;

import com.mongodb.MongoCommandException;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import org.bson.Document;

import java.util.ArrayList;

public class MongoCreateCollection {

    public static void main(String[] args) {

        try (var mongoClient = MongoClients.create("mongodb://localhost:27017")) {

            var database = mongoClient.getDatabase("testdb");

            try {

                database.createCollection("cars");
            } catch (MongoCommandException e) {

                database.getCollection("cars").drop();
            }

            var docs = new ArrayList<Document>();

            MongoCollection<Document> collection = database.getCollection("cars");

            var d1 = new Document("_id", 1);
            d1.append("name", "Audi");
            d1.append("price", 52642);
            docs.add(d1);

            var d2 = new Document("_id", 2);
            d2.append("name", "Mercedes");
            d2.append("price", 57127);
            docs.add(d2);

            var d3 = new Document("_id", 3);
            d3.append("name", "Skoda");
            d3.append("price", 9000);
            docs.add(d3);

            var d4 = new Document("_id", 4);
            d4.append("name", "Volvo");
            d4.append("price", 29000);
            docs.add(d4);

            var d5 = new Document("_id", 5);
            d5.append("name", "Bentley");
            d5.append("price", 350000);
            docs.add(d5);

            var d6 = new Document("_id", 6);
            d6.append("name", "Citroen");
            d6.append("price", 21000);
            docs.add(d6);

            var d7 = new Document("_id", 7);
            d7.append("name", "Hummer");
            d7.append("price", 41400);
            docs.add(d7);

            var d8 = new Document("_id", 8);
            d8.append("name", "Volkswagen");
            d8.append("price", 21600);
            docs.add(d8);

            collection.insertMany(docs);
        }
    }
}

```

该示例创建一个`cars`集合并将 9 个文档插入其中。

```java
try {

    database.createCollection("cars");
} catch (MongoCommandException e) {

    database.getCollection("cars").drop();
}

```

使用`createCollection()`方法创建一个新集合。 如果该集合已经存在，则将其删除。

```java
MongoCollection<Document> collection = database.getCollection("cars");

```

使用`getCollection()`方法创建文档的`MongoCollection`。

```java
var d1 = new Document("_id", 1);
d1.append("name", "Audi");
d1.append("price", 52642);
docs.add(d1);

```

创建一个新的`Document`。 它包含有关汽车的信息，包括其 ID，名称和价格。

```java
collection.insertMany(docs);

```

使用`insertMany()`方法将文档写入集合。

## Java MongoDB 从 JSON 创建集合

`JSON`类具有用于解析 JSON 文档的方法。 JSON （JavaScript 对象表示法）是一种轻量级的数据交换格式。 人类易于阅读和书写。

`com/zetcode/MongoCollectionFromJSON.java`

```java
package com.zetcode;

import com.mongodb.BasicDBObject;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import org.bson.types.ObjectId;

public class MongoCollectionFromJSON {

    public static void main(String[] args) {

        try (var mongoClient = MongoClients.create("mongodb://localhost:27017")) {

            var database = mongoClient.getDatabase("testdb");

            MongoCollection<Document> collection = database.getCollection("continents");

            var africa = BasicDBObject.parse("{_id : '" + ObjectId.get() + "', name : 'Africa'}");
            var asia = BasicDBObject.parse("{_id : '" + ObjectId.get() + "', name : 'Asia'}");
            var europe = BasicDBObject.parse("{_id : '" + ObjectId.get() + "', name : 'Europe'}");
            var america = BasicDBObject.parse("{_id : '" + ObjectId.get() + "', name : 'America'}");
            var australia = BasicDBObject.parse("{_id : '" + ObjectId.get() + "', name : 'Australia'}");
            var antarctica = BasicDBObject.parse("{_id : '" + ObjectId.get() + "', name : 'Antarctica'}");

            collection.insertOne(new Document(africa));
            collection.insertOne(new Document(asia));
            collection.insertOne(new Document(europe));
            collection.insertOne(new Document(america));
            collection.insertOne(new Document(australia));
            collection.insertOne(new Document(antarctica));
        }
    }
}

```

该示例从 JSON 数据创建`continents`集合。

```java
var africa = BasicDBObject.parse("{_id : '" + ObjectId.get() + "', name : 'Africa'}");

```

JSON 数据使用`BasicDBObject.parse`方法进行解析。

```java
collection.insertOne(new Document(africa));

```

`BasicDBObject`传递到`Document`，并通过`insertOne()`方法插入到集合中。

```java
> db.continents.find()
{ "_id" : "5d4af89645ffb636567b6448", "name" : "Africa" }
{ "_id" : "5d4af89645ffb636567b6449", "name" : "Asia" }
{ "_id" : "5d4af89645ffb636567b644a", "name" : "Europe" }
{ "_id" : "5d4af89645ffb636567b644b", "name" : "America" }
{ "_id" : "5d4af89645ffb636567b644c", "name" : "Australia" }
{ "_id" : "5d4af89645ffb636567b644d", "name" : "Antarctica" }

```

我们用`mongo`显示创建的集合。

## Java MongoDB 修改文件

`MongoCollection`的`deleteOne()`方法用于删除文档，`updateOne()`用于更新文档。

`com/zetcode/MongoModify.java`

```java
package com.zetcode;

import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import org.bson.Document;

import static com.mongodb.client.model.Filters.eq;

public class MongoModify {

    public static void main(String[] args) {

        try (var mongoClient = new MongoClient("localhost", 27017)) {

            var database = mongoClient.getDatabase("testdb");

            MongoCollection<Document> collection = database.getCollection("cars");

            collection.deleteOne(eq("name", "Skoda"));
            collection.updateOne(new Document("name", "Audi"),
                    new Document("$set", new Document("price", 52000)));

        }
    }
}

```

该示例删除包含 Skoda 的文档并更新 Audi 的价格。

```java
collection.deleteOne(eq("name", "Skoda"));

```

`deleteOne()`删除`Skoda`的文档。 `eq()`创建一个与所有文档匹配的过滤器，其中字段名称的值等于指定的值。

```java
collection.updateOne(new Document("name", "Audi"),
    new Document("$set", new Document("price", 52000)));

```

通过`updateOne()`方法将 Audi 的价格更改为 52,000。

```java
> db.cars.find()
{ "_id" : ObjectId("5d4d13d6463315268eb7376b"), "name" : "Audi", "price" : 52000 }
{ "_id" : ObjectId("5d4d13f5463315268eb7376c"), "name" : "Mercedes", "price" : 57127 }
{ "_id" : ObjectId("5d4d1408463315268eb7376e"), "name" : "Volvo", "price" : 29000 }
{ "_id" : ObjectId("5d4d140d463315268eb7376f"), "name" : "Bentley", "price" : 350000 }
{ "_id" : ObjectId("5d4d1411463315268eb73770"), "name" : "Citroen", "price" : 21000 }
{ "_id" : ObjectId("5d4d1415463315268eb73771"), "name" : "Hummer", "price" : 41400 }
{ "_id" : ObjectId("5d4d1419463315268eb73772"), "name" : "Volkswagen", "price" : 21600 }

```

我们使用`mongo`工具确认更改。

在本教程中，我们使用了 MongoDB 和 Java。 您可能也对 [Spring Boot MongoDB 教程](/springboot/mongodb/)， [MySQL Java 教程](/db/mysqljava/)或 [PostgreSQL Java 教程](/java/postgresql/)感兴趣。

列出[所有 Java 教程](/all/#java)。