一、声明
- 本文依赖于 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:mydb@127.0.0.1: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不对Snappy或Zstandard内置支持,因此驱动程序依赖现有的开源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:mydb@127.0.0.1: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:mydb@127.0.0.1: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还是比较简单的。