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、 elemMatch、slice和$.
注意:这里的
e
l
e
m
M
a
t
c
h
并
不
是
F
i
l
t
e
r
s
中
的
elemMatch并不是Filters中的
elemMatch并不是Filters中的elemMatch,而是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。使用
set更新size.uom的值为cm,status的值为p。使用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中所有写操作都是单个文档级别上的原子操作。