關於MongoDB的簡單理解(二)–Java篇

一、聲明

  • 本文依賴於 MongoDB JVM DRIVERS 4.1 版本編寫。
  • 本文案例依賴於 Maven 項目管理工具。

二、本文主要講解哪些內容?

  • 如何連接到MongoDB
  • 通過TLS/SSL連接MongoDB
  • 認證方式
  • 壓縮
  • 讀取/寫入操作
  • 創建索引
  • 文字搜尋
  • 網格FS

三、環境準備

官方描述:

  MongoDB驅動程序mongodb-driver-sync是同步Java驅動程序,僅包含MongoCollection符合新的交叉驅動程序CRUD規範的通用接口。

使用方式:

  添加如下依賴。

1 <dependencies>
2     <dependency>
3         <groupId>org.mongodb</groupId>
4         <artifactId>mongodb-driver-sync</artifactId>
5         <version>4.1.1</version>
6     </dependency>
7 </dependencies>

四、Java操作MongoDB

強心針:

  java操作MongoDb非常簡單,主要有以下幾個步驟:

  實例化MongoClient對象 –> 訪問數據庫  –> 訪問集合 –> 操作數據

1.如何連接到MongoDB?

官方描述:

  自3.7版本開始,建議使用 MongoClients.create() 創建連接,也可以用舊版的 MongoClient() 創建連接。

注意事項:

  默認情況下,3.5版本棄用的套接字保持活動設置以及套接字保持活動檢查現在處於啟用狀態。強烈建議該系統保持活動設置應該更短的超時配置。

連接 MongoDB單例 代碼實現:

 1 public static void main(String[] args) {
 2 
 3     // 連接方式1
 4     // 可以實例化一個不帶任何參數的MongoClient對象,以連接到端口在本地主機上運行的MongoDB實例27017
 5     MongoClient mongoClient = MongoClients.create();
 6 
 7     // 連接方式2
 8     // 可以顯式指定主機名,以連接到在端口上的指定主機上運行的MongoDB實例27017
 9     MongoClient mongoClient = MongoClients.create(
10             MongoClientSettings.builder()
11                     .applyToClusterSettings(builder ->
12                             builder.hosts(Arrays.asList(new ServerAddress("127.0.0.1")))).build()
13     );
14 
15     // 連接方式3
16     // 可以顯式指定主機名和端口:
17     MongoClient mongoClient = MongoClients.create(
18             MongoClientSettings.builder()
19                     .applyToClusterSettings(builder ->
20                             builder.hosts(Arrays.asList(new ServerAddress("127.0.0.1", 27017))))
21                     .build()
22     );
23 
24     // 連接方式4
25     // 顯式指定主機名和端口
26     MongoClient mongoClient = MongoClients.create("mongodb://127.0.0.1:27017");
27     
28 }

連接到副本集:

 1 public static void main(String[] args) {
 2 
 3     // 您可以使用來指定成員ConnectionString(指定副本集的至少兩個成員)
 4     MongoClient mongoClient = MongoClients.create("mongodb://host1:27017,host2:27017,host3:27017");
 5 
 6     // 使用副本集的至少一個成員和replicaSet(複製集)指定副本集名稱的選項
 7     MongoClient mongoClient = MongoClients.create("mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=myReplicaSet");
 8 
 9     // 您可以指定所有副本集成員的列表ServerAddress
10     MongoClient mongoClient = MongoClients.create(
11             MongoClientSettings.builder()
12                     .applyToClusterSettings(builder ->
13                             builder.hosts(Arrays.asList(
14                                     new ServerAddress("host1", 27017),
15                                     new ServerAddress("host2", 27017),
16                                     new ServerAddress("host3", 27017))))
17                     .build());
18 }

2.通過TLS/SSL連接MongoDB

官方描述:

  Java驅動程序使用JDK提供的TLS / SSL底層支持來支持與MongoDB服務器的TLS / SSL連接。

代碼示例:

 1 public static void main(String[] args) {
 2 
 3     // 直接指定TLS/SSL ConnectionString,使 ssl=true 為連接字符串的一部分
 4     MongoClient mongoClient = MongoClients.create("mongodb://localhost/?ssl=true");
 5 
 6     // 指定TLS/SSL MongoClientSettings,將enabled屬性設置為 true
 7     MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
 8             .applyToSslSettings(builder ->
 9                     builder.enabled(true))
10             .build();
11     MongoClient mongoClient1 = MongoClients.create(mongoClientSettings);
12 
13     // SSLContext: 此類的實例表示安全套接字協議的實現, 它是SSLSocketFactory、SSLServerSocketFactory和SSLEngine的工廠。
14     // 通過 SSLContext 指定 MongoClientSettings
15 
16     X509TrustManager x509m = new X509TrustManager() {
17 
18         @Override
19         public X509Certificate[] getAcceptedIssuers() {
20             return null;
21         }
22 
23         @Override
24         public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
25         }
26 
27         @Override
28         public void checkClientTrusted(X509Certificate[] chain,
29                                        String authType) throws CertificateException {
30         }
31     };
32 
33     // 獲取一個SSLContext實例
34     SSLContext sslContext = null;
35     try {
36         sslContext = SSLContext.getInstance("SSL");
37         // 初始化SSLContext實例
38         sslContext.init(null, new TrustManager[] { x509m },
39                 new java.security.SecureRandom());
40     } catch (Exception e) {
41         e.printStackTrace();
42     }
43 
44     SSLContext finalSslContext = sslContext;
45     MongoClientSettings settings = MongoClientSettings.builder()
46             .applyToSslSettings(builder -> {
47                 builder.enabled(true);
48                 builder.context(finalSslContext);
49             })
50             .build();
51     MongoClient client = MongoClients.create(settings);
52 
53     // 禁用主機名驗證
54     // 默認情況下,驅動程序確保服務器SSL證書中包含的主機名與構造時提供的主機名匹配
55     MongoClientSettings mongoClientSettings1 = MongoClientSettings.builder()
56             .applyToSslSettings(builder -> {
57                 builder.enabled(true);
58                 builder.invalidHostNameAllowed(true);
59             })
60             .build();
61     MongoClient client1 = MongoClients.create(mongoClientSettings1);
62 
63 }

3.認證方式

官方描述:

  • 在MongoDB 3.0中,MongoDB將默認的身份驗證機制從MongoDB-CR更改為SCRAM-SHA-1。
  • 在MongoDB 4.0中,取消了對不推薦使用的MongoDB-CR機制的支持,並添加了對SCRAM-SHA-256的支持。

代碼描述:

第一種方式:

 1 public static void main(String[] args) {
 2 
 3     // 用戶名
 4     String user = "mydb";
 5     // 定義用戶的源
 6     String source = "mydb";
 7     // 密碼字符數組
 8     char[] password = "mydb".toCharArray();
 9     
10     MongoCredential credential = MongoCredential.createScramSha1Credential(user, source, password);
11 
12     MongoClient mongoClient = MongoClients.create(
13             MongoClientSettings.builder()
14                     .applyToClusterSettings(builder ->
15                             builder.hosts(Arrays.asList(new ServerAddress("127.0.0.1", 27017))))
16                     .credential(credential)
17                     .build());
18 
19 }

第二種方式:

1 // 連接Mongo
2 MongoClient mongoClient = MongoClients.create("mongodb://mydb:[email protected]:27017");

憑證創建方式

SCRAM-SHA-1 憑證

1 // 用戶名
2 String user = "mydb";
3 // 定義用戶的源
4 String source = "mydb";
5 // 密碼字符數組
6 char[] password = "mydb".toCharArray();
7 
8 // 創建SCRAM-SHA-1 憑證
9 MongoCredential credential = MongoCredential.createScramSha1Credential(user, source, password);

SCRAM-SHA-256 憑證

1 // 用戶名
2 String user = "mydb";
3 // 定義用戶的源
4 String source = "mydb";
5 // 密碼字符數組
6 char[] password = "mydb".toCharArray();
7 
8 // SCRAM-SHA-256 憑證
9 MongoCredential credential = MongoCredential.createScramSha256Credential(user, source, password);

MONGODB-CR 憑證

1 // 用戶名
2 String user = "mydb";
3 // 定義用戶的源
4 String source = "mydb";
5 // 密碼字符數組
6 char[] password = "mydb".toCharArray();
7 
8 // MONGODB-CR 憑證
9 MongoCredential credential = MongoCredential.createMongoCRCredential(user, database, password);

X.509 憑證

1 // 用戶名
2 String user = "mydb";
3 
4 // X.509 憑證
5 MongoCredential credential = MongoCredential.createMongoX509Credential(user);

Kerberos (GSSAPI) 憑證

1 // 用戶名
2 String user = "mydb";
3 
4 // Kerberos (GSSAPI) 憑證
5 MongoCredential credential = MongoCredential.createGSSAPICredential(user);

LDAP (PLAIN) 憑證

1 // 用戶名
2 String user = "mydb";
3 // 密碼字符數組
4 char[] password = "mydb".toCharArray();
5 
6 // LDAP (PLAIN)憑證
7 MongoCredential credential = MongoCredential.createPlainCredential(user, "$external", password);

4. 壓縮

官方描述:

  Java驅動程序支持與MongoDB服務器之間的消息壓縮。該驅動程序實現了MongoDB服務器支持的三種算法:

  • Snappy:從3.4版本開始連接到MongoDB服務器時,可以使用Snappy壓縮。
  • Zlib:從3.6版本開始連接到MongoDB服務器時,可以使用Zlib壓縮。
  • Zstandard:從4.2版本開始連接到MongoDB服務器時,可以使用Zstandard壓縮。

代碼示例:

通過ConnectionString方式執行壓縮機:
 1 public static void main(String[] args) {
 2 
 3     // 通過ConnectionString方式執行壓縮機
 4     // 用Snappy壓縮
 5     ConnectionString connectionString = new ConnectionString("mongodb://localhost/?compressors=snappy");
 6     MongoClients.create(connectionString);
 7 
 8     // 用zlib壓縮
 9     ConnectionString connectionString = new ConnectionString("mongodb://localhost/?compressors=zlib");
10     MongoClient mongoClient = MongoClients.create(connectionString);
11 
12     // 用Zstandard壓縮
13     ConnectionString connectionString = new ConnectionString("mongodb://localhost/?compressors=zstd");
14     MongoClient mongoClient = MongoClients.create(connectionString);
15 
16     // 配置多個壓縮機
17     // 注意: 在所有情況下,驅動程序都將使用服務器為其提供支持的列表中的第一個壓縮器
18     ConnectionString connectionString = new ConnectionString("mongodb://localhost/?compressors=snappy,zlib,zstd");
19     MongoClient mongoClient = MongoClients.create(connectionString);
20 
21 }
通過MongoClientSettings指定壓縮機
 1 public static void main(String[] args) {
 2 
 3     // 通過MongoClientSettings指定壓縮機
 4 
 5     // 用Snappy壓縮
 6     MongoClientSettings settings = MongoClientSettings.builder()
 7             .compressorList(Arrays.asList(MongoCompressor.createSnappyCompressor()))
 8             .build();
 9     MongoClient client = MongoClients.create(settings);
10 
11     // 用zlib壓縮
12     MongoClientSettings settings = MongoClientSettings.builder()
13             .compressorList(Arrays.asList(MongoCompressor.createZlibCompressor()))
14             .build();
15     MongoClient client = MongoClients.create(settings);
16 
17     // 用Zstandard壓縮
18     MongoClientSettings settings = MongoClientSettings.builder()
19             .compressorList(Arrays.asList(MongoCompressor.createZstdCompressor()))
20             .build();
21     MongoClient client = MongoClients.create(settings);
22 
23     // 配置多個壓縮機
24     // 注意: 在所有情況下,驅動程序都將使用服務器為其提供支持的列表中的第一個壓縮器
25     MongoClientSettings settings = MongoClientSettings.builder()
26             .compressorList(Arrays.asList(MongoCompressor.createSnappyCompressor(),
27                     MongoCompressor.createZlibCompressor(),
28                     MongoCompressor.createZstdCompressor()))
29             .build();
30     MongoClient client = MongoClients.create(settings);
31 
32 }

注意:

  • 由於JDK不對SnappyZstandard內置支持,因此驅動程序依賴現有的開源Snappy和Zstandard實現
  • 驅動程序將根據ismaster命令響應中服務器通告的功能,如果有壓縮算法的話,會自動協商使用哪種壓縮算法。

Snappy擴展:

  snappy-java是snappy的Java端口,Snappy是Google開發的快速C ++壓縮器/解壓縮器。

  特點為 速度快內存佔用少跨平台使用簡單免費

  Snappy引入方式:

1 <dependency>
2    <groupId>org.xerial.snappy</groupId>
3    <artifactId>snappy-java</artifactId>
4    <version>(version)</version>
5    <type>jar</type>
6    <scope>compile</scope>
7 </dependency>

  Snappy代碼示例:

import org.xerial.snappy.Snappy;

String input = "Hello snappy-java! Snappy-java is a JNI-based wrapper of "
     + "Snappy, a fast compresser/decompresser.";
byte[] compressed = Snappy.compress(input.getBytes("UTF-8"));
byte[] uncompressed = Snappy.uncompress(compressed);

String result = new String(uncompressed, "UTF-8");
System.out.println(result);

//------------------------------
// 讀取/寫入大數據集(從1.1.3-M2開始)
import org.xerial.snappy.BitShuffle;

int[] data = new int[] {1, 3, 34, 43, 34};
byte[] shuffledByteArray = BitShuffle.shuffle(data);
byte[] compressed = Snappy.compress(shuffledByteArray);
byte[] uncompressed = Snappy.uncompress(compressed);
int[] result = BitShuffle.unshuffleIntArray(uncompress);

System.out.println(result);

Zstandard擴展:

  Zstd本機庫的JNI綁定為Android,Java和所有JVM語言提供了快速,高壓縮的無損算法。

  特點是 靜態壓縮/解壓縮方法、InputStream和OutputStream的實現、性能開銷小

  引入方式:

1 <dependency>
2     <groupId>com.github.luben</groupId>
3     <artifactId>zstd-jni</artifactId>
4     <version>VERSION</version>
5     <classifier>linux_amd64</classifier>
6 </dependency>

ismaster擴展:

  • isMaster返回描述mongod實例角色的文檔如果saslSupportedMechs指定了可選字段 ,該命令還將返回 用於創建指定用戶憑證的。
  • 如果實例是副本集的成員,則isMaster返回副本集配置和狀態的子集,包括實例是否為副本集副本。
  • 當發送到mongod不是副本集成員的實例時,isMaster返回此信息的子集。
  • MongoDB驅動程序客戶端用於 isMaster確定副本集成員的狀態並發現副本集的其他成員

  ismaster語法:

1 db.runCommand( { isMaster: 1 } )
2 
3 // 從MongoDB 4.0開始,該isMaster命令接受可選字段,以在其結果中返回附加字段並添加與該命令關聯的日誌注釋
4 db.runCommand( { isMaster: 1, saslSupportedMechs: "<db.username>", comment: <any> } )

5.讀取/寫入操作

  讀取和寫入比較簡單,這邊直接上代碼

使用Document類創建文檔:

 1 public static void main(String[] args) {
 2 
 3     // 連接方式
 4     MongoClient mongoClient = MongoClients.create("mongodb://mydb:[email protected]:27017");
 5 
 6     // 放問數據庫
 7     // 如果數據庫不存在,則在第一次為該數據庫 存儲數據 時,MongoDB會創建該數據庫
 8     // 注意:MongoDatabase 實例是不可變的
 9     MongoDatabase database = mongoClient.getDatabase("mydb");
10 
11     // 訪問集合
12     // 不存在集合,則在第一次為該集合 存儲數據 時,MongoDB會創建該集合
13     MongoCollection<Document> collection = database.getCollection("test");
14 
15     // 插入一個文件
16     // 創建文本對象
17     Document doc = new Document("name", "MongoDB")
18             .append("type", "database")
19             .append("count", 1)
20             .append("versions", Arrays.asList("v3.2", "v3.0", "v2.6"))
21             .append("info", new Document("x", 203).append("y", 102));
22 
23     //插入文件
24     collection.insertOne(doc);
25 
26     // 插入多個文件
27     List<Document> documentList = new ArrayList<>();
28     for (int i = 0; i < 100; i++){
29         documentList.add(new Document("i", i));
30     }
31     collection.insertMany(documentList);
32 
33     // 計算集合中的文檔
34     System.out.println("集合中的文檔的數量為:" + collection.countDocuments());
35 
36     // 查找集合中的第一個文檔
37     // 如果集合為空,則操作返回null
38     Document first = collection.find().first();
39     System.out.println("集合中的第一個文檔" + first.toJson());
40 
41     // 查找集合中的所有文檔
42     MongoCursor<Document> cursor = collection.find().iterator();
43     try {
44         while (cursor.hasNext()){
45             System.out.println(cursor.next().toJson());
46         }
47     }finally {
48         cursor.close();
49     }
50     // 查找集合中的所有文檔(不推薦做法--如果循環提前終止,則應用程序可能會泄漏游標)
51     for (Document cur : collection.find()) {
52         System.out.println(cur.toJson());
53     }
54 
55     // 獲取與過濾器匹配的單個文檔
56     Document singleDoc = collection.find(eq("i", 71)).first();
57     System.out.println("過濾器匹配的單個文檔" + singleDoc.toJson());
58 
59     // 獲取與過濾器匹配的所有文檔
60     Consumer<Document> printBlock = new Consumer<Document>() {
61         @Override
62         public void accept(Document document) {
63             System.out.println(document.toJson());
64         }
65     };
66     // "i" > 50
67     collection.find(gt("i",50)).forEach(printBlock);
68     // 50 < i <= 100
69     collection.find(and(gt("i", 50), lte("i", 100))).forEach(printBlock);
70 
71     // 更新單個文檔
72     UpdateResult updateResult = collection.updateOne(eq("i", 110), set("i", 10));
73     System.out.println("更新文件的數量為: " + updateResult.getModifiedCount());
74 
75     // 更新多個文件
76     // 對所有小於100的文檔,進行 +100 操作
77     UpdateResult updateResult1 = collection.updateMany(lt("i", 100), inc("i", 100));
78     System.out.println(updateResult1.getModifiedCount());
79 
80     // 刪除單個文檔
81     DeleteResult deleteOne = collection.deleteOne(eq("i", 110));
82     System.out.println("刪除單個文檔的數量" + deleteOne.getDeletedCount());
83 
84     // 刪除所有與過濾器匹配的文檔
85     // 刪除i大於或等於100的所有文檔
86     DeleteResult deleteMany = collection.deleteMany(gte("i", 100));
87     System.out.println("刪除多個文檔的數量" + deleteMany.getDeletedCount());
88 
89 }

使用POJO創建文檔(本例中使用lombok來簡化代碼):

  1)創建Address實體

 1 @Data
 2 @EqualsAndHashCode(callSuper = false)
 3 @Accessors(chain = true)
 4 @NoArgsConstructor                 //無參構造
 5 @AllArgsConstructor                //有參構造
 6 public final class Address {
 7 
 8     private String street;
 9 
10     private String city;
11 
12     private String zip;
13 
14 }

  2)創建Person實體

 1 @Data
 2 @EqualsAndHashCode(callSuper = false)
 3 @Accessors(chain = true)
 4 @NoArgsConstructor                 //無參構造
 5 @AllArgsConstructor                //有參構造
 6 public class Person {
 7 
 8     private ObjectId id;
 9 
10     private String name;
11 
12     private int age;
13 
14     private Address address;
15 
16     public Person(String name, int age, Address address) {
17         this.name = name;
18         this.age = age;
19         this.address = address;
20     }
21 }

  3)創建測試方法

 1 public static void main(String[] args) {
 2  
 3      // 連接Mongo
 4      MongoClient mongoClient = MongoClients.create("mongodb://mydb:[email protected]:27017");
 5  
 6      // 結合默認的編解碼器註冊表,並將其PojoCodecProvider配置為自動創建POJO Codec
 7      CodecRegistry pojoCodecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(),
 8              fromProviders(PojoCodecProvider.builder().automatic(true).build()));
 9  
10      // 放問數據庫
11      MongoDatabase database = mongoClient.getDatabase("mydb").withCodecRegistry(pojoCodecRegistry);
12  
13      // 配置了Pojo類型的實例
14      MongoCollection<Person> collection = database.getCollection("people", Person.class);
15  
16      // 插入一個人
17      Person person = new Person("Ada Byron", 20, new Address("St James Square", "London", "W1"));
18      collection.insertOne(person);
19  
20      // 插入很多人
21      List<Person> personList = Arrays.asList(
22          new Person("Charles Babbage", 45, new Address("5 Devonshire Street", "London", "W11")),
23          new Person("Alan Turing", 28, new Address("Bletchley Hall", "Bletchley Park", "MK12")),
24          new Person("Timothy Berners-Lee", 61, new Address("Colehill", "Wimborne", null))
25      );
26      collection.insertMany(personList);
27  
28      // 查詢集合
29      Consumer<Person> printBlock = new Consumer<Person>() {
30          @Override
31          public void accept(Person person) {
32              System.out.println(person);
33          }
34      };
35      collection.find().forEach(printBlock);
36  
37      // 符合條件的一個人
38      Person onePerson = collection.find(eq("address.city", "Wimborne")).first();
39      System.out.println("符合條件的人:" + onePerson);
40  
41      // 符合條件的很多人
42      collection.find(gt("age", 30)).forEach(printBlock);
43  
44      // 更新一個人
45      UpdateResult updateOne = collection.updateOne(eq("name", "Ada Byron"), combine(set("address.city", "bei jing"), set("age", "109")));
46      System.out.println("更新數量為:" + updateOne.getModifiedCount());
47  
48      // 更新很多人
49      UpdateResult updateMany = collection.updateMany(not(eq("address.zip", null)), set("address.zip", "MK15"));
50      System.out.println("更新數量為:" + updateMany.getModifiedCount());
51  
52      // 替換一個人
53      Person replacePerson = new Person("Xiao Ming", 29, new Address("bei jing", "bei jing", "W1"));
54      collection.replaceOne(eq("name", "Alan Turing"),replacePerson);
55  
56      DeleteResult deleteOne = collection.deleteOne(eq("address.city", "Wimborne"));
57      System.out.println("刪除數量:" + deleteOne.getDeletedCount());
58  
59      DeleteResult deleteMany = collection.deleteMany(eq("address.city", "bei jing"));
60      System.out.println("刪除數量:" + deleteMany.getDeletedCount());
61  
62      // 獲取集合名稱
63      database.listCollectionNames().forEach(System.out::println);
64  
65      // 慎用-- 刪除集合
66      collection.drop();
67      
68      // 投影文檔(指定返回結果)
69      collection.find().projection(fields(include("name", "age"),excludeId())).sort(Sorts.descending("age")).forEach(printBlock);
70 }

6.創建索引

官方描述:

  索引支持在MongoDB中高效執行查詢。可以在一個或多個字段上創建索引。

注意事項:

  MongoDB只在同一規範的索引不存在時創建索引。

代碼示例:

 1 public static void main(String[] args) {
 2 
 3     // 創建單個上升索引
 4     collection.createIndex(Indexes.ascending("name"));
 5     // 創建複合上升索引
 6     collection.createIndex(Indexes.ascending("age","name"));
 7 
 8     // 創建單個降序索引
 9     collection.createIndex(Indexes.descending("name"));
10     // 創建複合降序索引
11     collection.createIndex(Indexes.descending("age","name"));
12 
13     // 複合索引
14     collection.createIndex(Indexes.compoundIndex(Indexes.ascending("start"), Indexes.descending("name")));
15 
16     // 文字索引
17     collection.createIndex(Indexes.text("name"));
18 
19     // 散列指數
20     // 在_id字段上創建哈希索引
21     collection.createIndex(Indexes.hashed("_id"));
22     collection.listIndexes().forEach(System.out::println);
23 24 }

7.文字搜尋

官方描述:

  • 利用Atlas Search,您可以輕鬆地在MongoDB數據之上構建基於相關性的快速搜索功能
  • MongoDB使用文本索引和 $text查詢運算符更簡單的進行查詢操作
  • Java驅動程序提供了Filters.text()

代碼示例:

  文字搜索

1 // 例如,下面的代碼在name字段中執行文本搜索,查找單詞「bakery」或「coffee」。
2 long matchCount = collection.countDocuments(Filters.text("bakery coffee"));
3 System.out.println("Text search matches: " + matchCount);

  文字分數

1 // 文字分數
2 // 對於每個匹配的文檔,文本搜索都會分配一個分數,該分數表示文檔與指定的文本搜索查詢過濾器的相關性。要返回分數並按分數排序,請$meta在投影文檔和排序表達式中使用運算符
3 collection.createIndex(Indexes.text("i"));
4 MongoCursor<Document> iterator = collection.find(text("9")).projection(Projections.metaTextScore("score"))
5         .sort(Sorts.metaTextScore("score")).iterator();
6 while (iterator.hasNext()){
7         System.out.println(iterator.next().toJson());
8 }

  指定文本搜索選項

1 // 例如,以下文本搜索指定對單詞cafe執行文本搜索時的文本搜索語言選項:
2 long matchCountEnglish = collection.countDocuments(Filters.text("cafe", new TextSearchOptions().language("english")));
3 System.out.println("Text search matches (english): " + matchCountEnglish);

8.網格FS

官方描述:

  • GridFS是用於存儲和檢索超出BSON文檔大小限制16MB的文件的規範。
  • GridFS不會將文件存儲在單個文檔中,而是將文件劃分為多個部分或大塊,並將每個大塊存儲為單獨的文檔。
  • 查詢GridFS存儲中的文件時,Java驅動程序將根據需要重新組裝塊。

 代碼示例:

創建存儲桶

 1 public static void main(String[] args) {
 2  
 3      // 創建連接憑證
 4      // 用戶名
 5      String user = "mydb";
 6      // 數據源
 7      String source = "mydb";
 8      // 密碼
 9      char[] password = "mydb".toCharArray();
10  
11      // 憑證設置
12      MongoCredential credential = MongoCredential.createCredential(user, source, password);
13  
14      // MongoClient 連接設置
15      MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
16              .applyToClusterSettings(builder ->
17                      builder.hosts(Arrays.asList(new ServerAddress("127.0.0.1"))))
18              .credential(credential)
19              .build();
20  
21      // 創建Mongo連接
22      MongoClient mongoClient = MongoClients.create(mongoClientSettings);
23  
24      // 選擇數據庫
25      MongoDatabase database = mongoClient.getDatabase("mydb");
26  
27      // GridFS將文件存儲在兩個集合中:一個chunks集合存儲文件塊,一個 files集合存儲文件元數據。這兩個集合位於公共存儲桶中,並且集合名稱以存儲桶名稱為前綴。
28      // 第一次將數據上傳到GridFS存儲桶時,GridFS將在files和chunks集合上自動創建索引。
29      // Create a gridFSBucket using the default bucket name "fs"
30      // 使用默認的bucket名稱「fs」創建一個gridFSBucket
31      GridFSBucket gridFSBucket = GridFSBuckets.create(database);
32      
33     // 指定存儲桶名稱(創建存儲桶方式2)
34     // GridFSBucket gridFSFilesBucket = GridFSBuckets.create(database, "files");
35  
36 }

上傳文件

UploadFromStream方式

  該GridFSBucket.uploadFromStream方法讀取an的內容InputStream並將其保存到中GridFSBucket

 1 // 使用默認的bucket名稱「fs」創建一個gridFSBucket
 2     GridFSBucket gridFSBucket = GridFSBuckets.create(database);
 3 
 4     // UploadFromStream
 5     // Get the input stream
 6     // 獲取輸入流
 7     try {
 8         InputStream streamToUploadFrom = new FileInputStream(new File("D:\\ServiceInfoQuery.pdf"));
 9         // Create some custom options
10         // 創建一些自定義選項
11         GridFSUploadOptions options = new GridFSUploadOptions()
12                 .chunkSizeBytes(358400)
13                 .metadata(new Document("type", "presentation"));
14 
15         ObjectId fileId = gridFSBucket.uploadFromStream("mongodb-tutorial1", streamToUploadFrom, options);
16         streamToUploadFrom.close();
17         System.out.println("The fileId of the uploaded file is: " + fileId.toHexString());
18 
19     } catch (FileNotFoundException e) {
20         e.printStackTrace();
21     } catch (IOException e){
22         e.printStackTrace();
23     }

OpenUploadStream方式

  該GridFSUploadStream緩存數據,直到它到達chunkSizeBytes,然後插入塊到chunks集合。GridFSUploadStream關閉時,最後的塊寫入和文件元數據插入到files集合。

 1     // 指定存儲桶名稱(創建存儲桶方式2)
 2     GridFSBucket gridFSFilesBucket = GridFSBuckets.create(database, "files");
 3 
 4     // OpenUploadStream
 5     GridFSUploadOptions options = new GridFSUploadOptions()
 6             .chunkSizeBytes(358400)
 7             .metadata(new Document("type", "presentation"));
 8 
 9     GridFSUploadStream uploadStream = gridFSFilesBucket.openUploadStream("mongodb-tutorial-2", options);
10 
11     try {
12         byte[] data = Files.readAllBytes(new File("D:\\gridfs.pdf").toPath());
13         uploadStream.write(data);
14         uploadStream.close();
15         System.out.println("The fileId of the uploaded file is: " + uploadStream.getObjectId().toHexString());
16     } catch (IOException e) {
17         e.printStackTrace();
18     }

查找文件

 1     Consumer<GridFSFile> printBlock = new Consumer<GridFSFile>() {
 2         @Override
 3         public void accept(GridFSFile gridFSFile) {
 4             System.out.println(gridFSFile.getFilename());
 5         }
 6     };
 7 
 8     // 查找存儲在GridFS中的文件
 9     // 打印出每個存儲文件的文件名
10     gridFSBucket.find().forEach(printBlock);

下載文件

  通過ObjectId下載

 1     // 從MongoDB中讀取內容,並將數據直接寫入提供的OutputStream
 2     // 通過ObjectId 下載
 3     try {
 4 
 5         FileOutputStream streamToDownloadTo = new FileOutputStream("/tmp/mongodb-tutorial3.pdf");
 6 
 7         ObjectId objectId = gridFSBucket.find().first().getObjectId();
 8 
 9         gridFSBucket.downloadToStream(objectId, streamToDownloadTo);
10 
11         streamToDownloadTo.close();
12 
13         System.out.println(streamToDownloadTo.toString());
14 
15     } catch (FileNotFoundException e) {
16         e.printStackTrace();
17     } catch (IOException e) {
18         e.printStackTrace();
19     }

  通過文件名下載

 1     // 通過 文件名 下載
 2     try {
 3         FileOutputStream streamToDownloadTo = new FileOutputStream("/tmp/mongodb-tutorial1.pdf");
 4         GridFSDownloadOptions downloadOptions = new GridFSDownloadOptions().revision(0);
 5     // 兩種方式選擇一種即可
 6         gridFSBucket.downloadToStream(gridFSBucket.find().first().getFilename(), streamToDownloadTo, downloadOptions);
 7         // gridFSBucket.downloadToStream("mongodb-tutorial", streamToDownloadTo, downloadOptions);
 8         streamToDownloadTo.close();
 9     } catch (FileNotFoundException e) {
10         e.printStackTrace();
11     } catch (IOException e) {
12         e.printStackTrace();
13     }

讀取文件

  通過ObjectId讀取文件

1     // 通過 ObjectId 讀取文件
2     ObjectId objectId = gridFSBucket.find().first().getObjectId();
3     GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(objectId);
4     int fileLength = (int) downloadStream.getGridFSFile().getLength();
5     System.out.println("文件長度" + fileLength);
6     byte[] bytesToWriteTo = new byte[fileLength];
7     downloadStream.read(bytesToWriteTo);
8     downloadStream.close();
9     System.out.println(new String(bytesToWriteTo, StandardCharsets.UTF_8));

  通過名稱讀取文件

 1     // 通過名稱讀取文件
 2     String filename = gridFSBucket.find().first().getFilename();
 3     GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(filename);
 4     int fileLength = (int) downloadStream.getGridFSFile().getLength();
 5     System.out.println("文件長度" + fileLength);
 6     byte[] bytesToWriteTo = new byte[fileLength];
 7     downloadStream.read(bytesToWriteTo);
 8     downloadStream.close();
 9 
10     System.out.println(new String(bytesToWriteTo, StandardCharsets.UTF_8));

重命名文件

1     // 重命名文件
2     // 注意
3     // 該rename方法要求使用 ObjectId 而不是 filename 來確保重命名正確的文件。
4     // 要重命名同一文件名的多個修訂,請首先檢索文件的完整列表。然後對於每個應重命名的文件,然後rename使用相應的_id
5     ObjectId objectId = gridFSBucket.find().first().getObjectId();
6     gridFSBucket.rename(objectId, "test");

刪除文件

1     // 刪除文件
2     // ObjectId of a file uploaded to GridFS
3     // 上載到GridFS的文件的ObjectId
4     ObjectId objectId = gridFSBucket.find().first().getObjectId();
5     gridFSBucket.delete(objectId);

四、總結

  總的來說,java操作MongoDB還是比較簡單的。