MongoDB自学笔记(1)-JAVA-MongoDB-Driver中的CRUD操作

MongoDB v3.6

前提

org.mongodb mongodb-driver 3.6.4
连接到MongoDB

方式1.MongoClient mongoClient = new MongoClient();//即使在多线程下,我们也只需要一个MongoClient示例。因为MongoClient是不可变类。线程安全
方式2.MongoClient mongoClient = new MongoClient( String ip );
方式3.显式指定主机名和端口:MongoClient mongoClient = new MongoClient( “localhost” , 27017 );
方式4.指定 MongoClientURI连接字符串:
ongoClientURI connectionString = new MongoClientURI(“mongodb://localhost:27017”);
MongoClient mongoClient = new MongoClient(connectionString);

访问database

MongoDatabase database = mongoClient.getDatabase(“数据库名称”);//如果数据库不存在,则在您第一次为该数据库存储数据时,MongoDB会创建该数据库。MongoDatabase是不可变的。

访问collection

MongoCollection collection = database.getCollection(“collectionName”);//如果不存在集合,则在您第一次为该集合存储数据时,MongoDB会创建该集合。MongoCollection 实例是不可变的。

增加操作

插入一个文档

com.mongodb.client.MongoCollection.insertOne()将单个文档插入到集合中。

在MongoDB中,存储在集合中的每个文档都需要一个惟一的_id字段作为主键。如果插入的文档省略了_id字段,MongoDB驱动程序将自动为_id字段生成ObjectId。

Document canvas = new Document(“item”, “canvas”)
.append(“qty”, 100)
.append(“tags”, singletonList(“cotton”));

Document size = new Document(“h”, 28)
.append(“w”, 35.5)
.append(“uom”, “cm”);
canvas.put(“size”, size);

collection.insertOne(canvas);

插入多个文档

使用collection的insertMany()方法:

List documents = new ArrayList();
for (int i = 0; i < 100; i++) {
documents.add(new Document(“i”, i));
}
collection.insertMany(documents);

插入POJO

1.创建一个自定义CodecRegistry:在将POJO与驱动程序一起使用之前,您需要配置,CodecRegistry 以包括一个编解码器来处理bsonPOJO的来回转换。最简单的方法是使用 PojoCodecProvider.builder()来创建和配置CodecProvider。
示例将默认的编解码器注册表与PojoCodecProvider配置为自动创建结合起来PojoCodecs:
CodecRegistry pojoCodecRegistry = fromRegistries(MongoClient.getDefaultCodecRegistry(),
fromProviders(PojoCodecProvider.builder().automatic(true).build()));

2.使用CodecRegistry

1.在实例化MongoClient对象时进行设置:
 MongoClient mongoClient = new MongoClient("localhost",	MongoClientOptions.builder().codecRegistry(pojoCodecRegistry).build());
	 
2.与MongoDatabase一起使用:
	database = database.withCodecRegistry(pojoCodecRegistry);

3.与MongoCollection一起使用:
	collection = collection.withCodecRegistry(pojoCodecRegistry);

查找操作

以下所有的find方法来自Collection
所有的过滤器方法,如:eq,lt均来自com.mongodb.client.model.Filters
示例:
collection.insertMany(asList(
Document.parse("{ item: ‘journal’, qty: 25, size: { h: 14, w: 21, uom: ‘cm’ }, status: ‘A’ }"),
Document.parse("{ item: ‘notebook’, qty: 50, size: { h: 8.5, w: 11, uom: ‘in’ }, status: ‘A’ }"),
Document.parse("{ item: ‘paper’, qty: 100, size: { h: 8.5, w: 11, uom: ‘in’ }, status: ‘D’ }"),
Document.parse("{ item: ‘planner’, qty: 75, size: { h: 22.85, w: 30, uom: ‘cm’ }, status: ‘D’ }"),
Document.parse("{ item: ‘postcard’, qty: 45, size: { h: 10, w: 15.25, uom: ‘cm’ }, status: ‘A’ }")
));

匹配嵌入/嵌套文档

a) 要在一个内嵌/嵌套文档的字段上指定相等条件,请使用筛选器文档eq(filedName,Value ),其中Value是要匹配的文档。
b) 在整个嵌入式文档上的相等匹配要求精确匹配指定的文档,包括字段顺序。

嵌套字段查询

a) 要在嵌入/嵌套文档的字段上指定查询条件,请使用点符号,如:(“field.nestedField”)。使用点符号进行查询时,字段和嵌套字段必须放在引号内。
find(eq(“size.uom”, “in”));//查询字段uom嵌套在size字段等于“in”的所有文档在嵌套字段上指定相等匹配: find (eq(“size.uom”, “in”));
b) 相等条件之外,MongoDB Filters还提供各种查询操作符来指定筛选条件
find(lt(“size.h”, 15));// 查询使用了嵌入在size字段中的字段h上的小于操作符($lt)
c) 指定AND条件
find(and(
lt(“size.h”, 15),
eq(“size.uom”, “in”),
eq(“status”, “D”))); 查询选择嵌套字段h小于15、嵌套字段uom等于“in”、状态字段等于“D”的所有文档

查询数组

collection.insertMany(asList(
Document.parse("{ item: ‘journal’, qty: 25, tags: [‘blank’, ‘red’], dim_cm: [ 14, 21 ] }"),
Document.parse("{ item: ‘notebook’, qty: 50, tags: [‘red’, ‘blank’], dim_cm: [ 14, 21 ] }"),
Document.parse("{ item: ‘paper’, qty: 100, tags: [‘red’, ‘blank’, ‘plain’], dim_cm: [ 14, 21 ] }"),
Document.parse("{ item: ‘planner’, qty: 75, tags: [‘blank’, ‘red’], dim_cm: [ 22.85, 30 ] }"),
Document.parse("{ item: ‘postcard’, qty: 45, tags: [‘blue’], dim_cm: [ 10, 15.25 ] }")
));
a) 要在数组上指定相等条件,请使用筛选器文档eq(field,Value ),其中Value是要匹配的精确数组,包括元素的顺序。
如:find(eq(“tags”, asList(“red”, “blank”)));
b) 如果希望找到一个同时包含“red”和“blank”元素的数组,而不考虑数组中的顺序或其他元素,使用all()操作
i. 如:find(all(“tags”, asList(“red”, “blank”)));

查询数组的元素

a) 要查询数组字段是否包含至少一个具有指定值的元素,可以使用filter eq(, ),其中是元素值。
i. find(eq(“tags”, “red”));//查询所有文档,其中tags是一个数组,其中包含字符串“red”作为其元素之一
b) 指定数组字段中元素的条件,在查询筛选器文档中使用查询操作符。
and(gt(, ), lt(, ) …)
i. 如:find(gt(“dim_cm”, 25));// 查询数组dim_cm中包含至少一个值大于25的元素的所有文档。

为数组元素指定多个条件

在数组元素上指定复合条件时,可以指定查询:使单个数组元素满足这些条件,或者数组元素的任何组合满足这些条件。
a) 在数组元素上查询具有复合筛选条件的数组
i. 如:查询文档,其中的dim_cm数组包含满足符合查询条件的元素。例如,一个元素可以满足大于15的条件,另一个元素可以满足小于20的条件,或者单个元素可以同时满足这两个条件:find(gt(“dim_cm”,15),lt(“dim_cm”,20))
b) 查询满足多个条件的数组元素
i. 使用$elemMatch操作符在数组的元素上指定多个条件,以便至少有一个数组元素满足所有指定的条件。elemMatch(FiledName,filter) 表示已经选择了filedName的元素,再用filter过滤其中的元素
find(elemMatch(“dim_cm”, Document.parse("{ $gt: 22, KaTeX parse error: Expected 'EOF', got '}' at position 8: lt: 30 }̲")));//dim_cm数组…gt) 22且小于($lt) 30的元素

根据数组索引位置查询元素

a) 使用点符号,您可以在数组的特定索引或位置指定元素的查询条件。该数组使用从零开始的索引。注意使用点符号进行查询时,字段和嵌套字段必须放在引号内。
i. find(gt(“dim_cm.1”, 25));

按数组长度查询数组

a) 使用$size操作符按元素数量查询数组
i. find(size(“tags”, 3));// 选择数组标记中有3个元素的文档。

查询嵌入文档的数组

示例:
collection.insertMany(asList(
Document.parse("{ item: ‘journal’, instock: [ { warehouse: ‘A’, qty: 5 }, { warehouse: ‘C’, qty: 15 } ] }"),
Document.parse("{ item: ‘notebook’, instock: [ { warehouse: ‘C’, qty: 5 } ] }"),
Document.parse("{ item: ‘paper’, instock: [ { warehouse: ‘A’, qty: 60 }, { warehouse: ‘B’, qty: 15 } ] }"),
Document.parse("{ item: ‘planner’, instock: [ { warehouse: ‘A’, qty: 40 }, { warehouse: ‘B’, qty: 5 } ] }"),
Document.parse("{ item: ‘postcard’, instock: [ { warehouse: ‘B’, qty: 15 }, { warehouse: ‘C’, qty: 35 } ] }")
));
a) 示例选择instock数组中的元素与指定文档匹配的所有文档:
i. find(eq(“instock”, Document.parse("{ warehouse: ‘A’, qty: 5 }")));
b) 在整个嵌入/嵌套文档上的相等匹配要求精确匹配指定的文档,包括字段顺序。例如,以下查询不匹配库存集合中的任何文档:
i. find(eq(“instock”, Document.parse("{qty: 5, warehouse: ‘A’ }")));

在数组中文档的字段上指定查询条件

a) 指定嵌入在文档数组中的字段的查询条件。如果您不知道嵌套在数组中的文档的索引位置,请将数组字段的名称与嵌套文档中的点(.)和字段的名称连接起来。
i. 示例选择instock数组中至少有一个嵌入文档的所有文档,该文档包含值小于或等于20的字段qty: find(lte(“instock.qty”, 20));
b) 使用数组索引查询嵌入文档中的字段。使用点符号,您可以为文档中特定索引或数组位置的字段指定查询条件。该数组使用从零开始的索引。
i. 示例选择instock数组的第一个元素为文档的所有文档,该文档包含值小于或等于20的字段qty:find(lte(“instock.0.qty”, 20));
ii. 实例选择instock数组中第一个元素为文档的所有文档,该文档包括值为‘C’的warehouse: eq(“instock.0.warehouse”,‘C’)

为文档数组指定多个条件

当在文档数组中嵌套的多个字段上指定条件时,可以指定查询,使单个文档满足这些条件,或者数组中的任何文档组合(包括单个文档)满足这些条件。
a) 单个嵌套文档满足嵌套字段上的多个查询条件. 使用$elemMatch操作符在嵌入文档数组上指定多个条件,以便至少有一个嵌入文档满足所有指定的条件。
i. 示例查询instock数组中至少有一个嵌入文档的文档,该文档包含字段qty等于5和字段warehouse等于A:
find(elemMatch(“instock”, Document.parse("{ qty: 5, warehouse: ‘A’ }")));
ii.示例查询instock数组中至少有一个嵌入文档的文档,该文档包含大于10且小于或等于20的字段qty:
find(elemMatch(“instock”, Document.parse("{ qty: { $gt: 10, $lte: 20 } }")));

元素的组合满足条件

如果数组字段上的复合查询条件不使用$elemMatch操作符,查询将选择数组中包含满足条件的任何元素组合的文档。
a ) 以下查询匹配在instock数组中嵌套的任何文档的qty字段大于10,而数组中的任何文档(但不一定是相同的嵌入文档)的qty字段小于或等于20的文档: find(and(gt(“instock.qty”, 10), lte(“instock.qty”, 20)));
b ) 示例查询的文档中,instock数组至少有一个嵌入文档,其中包含字段qty等于5,并且至少有一个嵌入文档(但不一定是相同的嵌入文档),其中包含字段warehouse等于A: find(and(eq(“instock.qty”, 5), eq(“instock.warehouse”, “A”)));

限制查询返回的字段

默认情况下,MongoDB中的查询返回匹配文档中的所有字段。要限制MongoDB发送给应用程序的数据量,可以包含一个投影文档来指定或限制字段返回。
示例:
collection.insertMany(asList(
Document.parse("{ item: ‘journal’, status: ‘A’, size: { h: 14, w: 21, uom: ‘cm’ }, instock: [ { warehouse: ‘A’, qty: 5 }]}"),
Document.parse("{ item: ‘notebook’, status: ‘A’, size: { h: 8.5, w: 11, uom: ‘in’ }, instock: [ { warehouse: ‘C’, qty: 5}]}"),
Document.parse("{ item: ‘paper’, status: ‘D’, size: { h: 8.5, w: 11, uom: ‘in’ }, instock: [ { warehouse: ‘A’, qty: 60 }]}"),
Document.parse("{ item: ‘planner’, status: ‘D’, size: { h: 22.85, w: 30, uom: ‘cm’ }, instock: [ { warehouse: ‘A’, qty: 40}]}"),
Document.parse("{ item: ‘postcard’, status: ‘A’, size: { h: 10, w: 15.25, uom: ‘cm’ }, "
+ “instock: [ { warehouse: ‘B’, qty: 15 }, { warehouse: ‘C’, qty: 35 } ] }”)
));
a ) 返回匹配文档中的所有字段. 如果不指定投影,可以指定com.mongodb.client.MongoCollection.find方法返回匹配文档中的所有字段。
collection.find(eq(“status”, “A”));//返回库存集合中状态为“A”的所有文档的所有字段
相当于sql语句中的SELECT * from inventory WHERE status = “A”
b ) 只返回指定的字段和_id字段
通过在投影文档中将设置为1,一个投影可以显式地包含多个字段。下面的操作返回与查询匹配的所有文档。在结果集中,只有item、status和默认情况下在匹配文档中返回的_id字段。要指定投影文档,链接com.mongodb.client.FindIterabl.projection()方法。使用com.mongodb.client.model.Projections类来创建投影文档。find().projection();
find(eq(“status”, “A”)).projection(include(“item”, “status”));
相等于sql:SELECT _id, item, status from inventory WHERE status = “A”
c )去掉id字段. 可以在投影中将_id字段设置为0,从而从结果中删除_id字段
find(eq(“status”, “A”)).projection(fields(include(“item”, “status”), excludeId()));
相当于sql中:
SELECT item, status from inventory WHERE status = “A”

**注意:除了_id字段之外,不能在投影文档中组合include和exclude

语句。**
d) 返回除了被排除的字段外的所有字段
find(eq(“status”, “A”)).projection(exclude(“item”, “status”));

返回嵌入文档中的特定字段。可以在嵌入式文档中返回特定的字段。使用点符号来引用嵌入的字段,并在投影文档中将其设置为1。
find(eq("status", "A")).projection(include("item", "status", "size.uom"));
	返回
	•	The _id field (returned by default),
	•	The item field,
	•	The status field,
	•	The uom field in the size document.
在嵌入文档中除开特定字段. 可以在嵌入式文档中禁用特定字段。使用点符号引用投影文档中的嵌入字段并将其设置为0(excluede())。
a)	示例指定一个投影来排除size Document中的uom字段,所有其他字段在匹配的文档中返回
	i.	find(eq("status", "A")).projection(exclude("size.uom"));
在数组中嵌入文档上的投影

a) 使用点符号来投影嵌入在数组中的文档中的特定字段。
find(eq(“status”, “A”)).projection(include(“item”, “status”, “instock.qty”));
返回:
• The _id field (returned by default),
• The item field,
• The status field,
• The qty field in the documents embedded in the instock array.

回数组中特定的项目数组元素。对于包含数组的字段,MongoDB提供了以下用于操作数组的投影操作符: e l e m M a t c h 、 elemMatch、 elemMatchslice和$.

注意:这里的 e l e m M a t c h 并 不 是 F i l t e r s 中 的 elemMatch并不是Filters中的 elemMatchFilterselemMatch,而是Projections中的操作符。
find(eq(“status”, “A”)).projection(fields(include(“item”, “status”), slice(“instock”,-1)));
使用#slice投影操作符返回instock数组中的最后一个元素。

//使用$elemMatch投影操作符返回tags数组中值为'red'的元素.
find(eq("status", "A")).projection(fields(include("item", "status"), Projections.elemMatch("tags",Document.parse("{$eq:'red'}"))));
查询空字段或缺少字段

Mongodb中不同的查询操作符以不同的方式处理null值。
a) eq过滤器,eq(fieldname,null):查询匹配的文档要么包含值为null的fieldName字段要么不包含fieldName字段。
b) type过滤器,type(fieldname, BsonType.NULL):查询只匹配包含值为null的item字段的文档。即该field 的value是BsonType.NULL类型的
c) 存在检查。Exists(fieldname, false):查询只返回不包含fieldName字段的文档

更新操作

com.mongodb.client.model.Updates提供了方便创建更新文档的方法。
比如说 combine(set( , ), set(, ) )
如果字段不存在,一些更新操作符如$set将创建该字段。

示例1 使用updateOne()在inventory collection中更新”item”等于 "paper"的第一个文档:
updateOne(eq(“item”, “paper”),combine(set(“size.uom”, “cm”), set(“status”, “P”), currentDate(“lastModified”)));
上面的语句使用 s e t 更 新 s i z e . u o m 的 值 为 c m , s t a t u s 的 值 为 p 。 使 用 set更新size.uom的值为cm,status的值为p。使用 setsize.uomcmstatusp使currentDate操作符将lastModified字段的值更新为当前日期。如果lastModified字段不存在,$currentDate操作符将创建该字段

示例2 更新多个文档。使用updateMany()更新nventory collection 中将qty的值小于50的所有文档。
updateMany(lt(“qty”, 50),combine(set(“size.uom”, “in”), set(“status”, “P”),currentDate(“lastModified”)));

示例3 替换一个文档。
**注意:**要替换除_id字段外的整个文档内容。将一个全新的文档作为第二个参数传递给replaceOne().替换文档时,替换文档必须只包括字段/值对。即不包括更新操作符表达式。替换文档可以具有与原始文档不同的字段。在替换文档中,可以省略_id字段。因为_id字段是不可变的,但是,如果包含_id字段,则它必须具有与当前值相同的值。即通过_id来替换。
replaceOne(eq(“item”, “paper”),Document.parse("{ item: ‘paper’, instock: [ { warehouse: ‘A’, qty: 60 }, { warehouse: ‘B’, qty: 40 } ] }"));//替换inventory collection中item等于”paper”的第一个文档

跟新操作的行为

1.原子性:Mongodb中的所有写操作都是单个文档级别上的原子操作。
2._id领域:一旦设置好,你就不能更新_id字段的值,也不能用具有不同_id字段值的替换文档替换现有文档。
3.字段顺序:除了以下情况外,MongoDB在写入操作中保留了文档字段的顺序
例外:1._id字段总是文档中的第一个字段
2.包括重命名字段名的更新可能会导致文档中字段的重新排序。

Upsert Option

如果更新和替换方法包括com.omgodb.client.model.UpdateOptions参数指定upsert(true),且没有文档匹配指定的过滤器,然后操作将创建一个新文档并插入它。如果存在匹配文档,则操作将修改或替换匹配文档。

删除操作

1.删除所有文档:
传递一个空的org.bson.Document对象作为com.mongodb.client.MongoCollection.deleteMany方法的过滤器。如:
deleteMany(new Document()); deleteMany()返回一个具有删除操作状态信息的 com.mongodb.client.result的实例。

2.删除所有匹配条件的文档
可以指定标识要删除的文档过滤器,过滤器使用与读取操作相同的语法。
要删除符合删除条件的所有文档,com.mongodb.client.MongoCollection.deleteMany方法传递一个过滤器参数。
deleteMany(eq(“status”, “A”));//删除status字段等于”A”的所有文档。

3.只删除一个匹配条件的文档。
要删除最多一个匹配指定过滤器的文档(即使多个文档可能匹配指定过滤器),使用deleteOne()方法:deleteOne(eq(“status”, “D”));//删除status等于”A”的第一个文档

删除的行为

索引:delete操作不会删除索引,即使是从一个集合中删除所有文档也是如此
原子性:MongoDB中所有写操作都是单个文档级别上的原子操作。

以上所有内容均是我整理自MongoDB的官方文档。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值