MongoDB7.0--SpringBoot单集合操作

摘要

spring-boot 与 MongoDB 的版本对应关系

  • spring-data-mongodbMongoDB版本对应关系可以参看官方文档

  • spring-boot-starter-data-mongodbspring-data-mongodb 版本对应关系

spring-boot-starter-data-mongodb 版本 spring-data-mongodb 版本 MongoDB Server 版本 Java Driver Version
3.2.x 4.2.x 6.0.x,7.0.x 4.11.x
3.1.x 4.1.x 6.0.x,7.0.x 4.9.x
3.0.x 4.0.x 6.0.x 4.7.x
2.7.x 3.4.x 5.0.x 4.6.x
2.6.x 3.3.x 5.0.x 4.4.x
2.5.x 3.2.x 4.4.x 4.1.x
2.4.x 3.1.x 4.4.x 4.1.x
2.3.x 3.0.x 4.4.x 4.0.x
2.2.x 2.2.x 4.2.x 3.11.x
2.1.x 2.1.x 4.0.x 3.8.x
2.0.x 2.0.x 3.4.x 3.5.x
1.10.x 1.10.x 2.4.x 2.10.x,2.11.x

SpringBoot整合MongoDB

  • 引入依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
  • 配置yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
data:
mongodb:
uri: mongodb://root:password@127.0.0.1:27017/mytest?authSource=admin
#uri等同于下面的配置
# database: mytest # 数据库名
# host: 127.0.0.1
# port: 27017
# username: root
# password: password
#a uthentication-database: admin

# 复制集
# uri: mongodb://user:password@127.0.0.1:27040,127.0.0.1:27041,127.0.0.1:27042/mytest?authSource=admin&readPreference=primaryPreferred
  • 配置类:去掉_class属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
public class MongoConfig {

/**
* 定制TypeMapper去掉_class属性
*/
@Bean
MappingMongoConverter mappingMongoConverter(
MongoDatabaseFactory mongoDatabaseFactory,
MongoMappingContext context, MongoCustomConversions conversions) {

DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDatabaseFactory);
MappingMongoConverter mappingMongoConverter =
new MappingMongoConverter(dbRefResolver, context);
mappingMongoConverter.setCustomConversions(conversions);

//构造DefaultMongoTypeMapper,将typeKey设置为空值
mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));

return mappingMongoConverter;
}
}

查询

  • Mongo语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 查询集合中的若干文档
db.collection.find(query, projection)

# 查询集合中的第一个文档
db.collection.findOne(query, projection)

# 如果你需要以易读的方式来读取数据,可以使用pretty()方法
db.collection.find().pretty()

# 排序,1 为升序排列,而 -1 是用于降序排列
db.collection.find(query, projection).sort({field:-1})

# 分页
# .skip(16) 表示跳过前面 16 条记录,即前两页的所有记录.
# .limit(8) 表示返回 8 条记录,即第三页的所有记录。
db.collection.find().skip(16).limit(8)

# 查询记录数
db.collection.countDocuments()
  • query :可选,使用查询操作符指定查询条件

  • projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。投影时,_id为1的时候,其他字段必须是1;_id是0的时候,其他字段可以是0;如果没有_id字段约束,多个其他字段必须同为0或同为1。

  • 查询操作符

操作符 解释 示例 示例解释
$lt 小于 db.collection.find({ "age": { "$lt": 25 } }) 查询年龄小于 25 的文档
$lte 小于等于 db.collection.find({ "age": { "$lte": 25 } }) 查询年龄小于等于 25 的文档
$gt 大于 db.collection.find({ "age": { "$gt": 25 } }) 查询年龄大于 25 的文档
$gte 大于等于 db.collection.find({ "age": { "$gte": 25 } }) 查询年龄大于等于 25 的文档
$ne 不等于 db.collection.find({ "age": { "$ne": 25 } }) 查询年龄不等于 25 的文档
$in 在指定数组中 db.collection.find({ "age": { "$in": [20, 25] } }) 查询年龄存在并且在指定数组中的文档
$nin 不在指定数组中 db.collection.find({ "age": { "$nin": [20, 25] } }) 查询年龄不存在或者不在指定数组中的文档
$or 匹配两个或多个条件中的一个 db.collection.find({ "$or": [ { "age": 20 }, { "salary": { "$gt": 8000 } } ] }) 查询年龄为 20 或者薪资大于 8000 的文档
$and 匹配全部条件 db.collection.find({ "$and": [ { "age": 20 }, { "salary": { "$gt": 8000 } } ] }) 查询年龄为 20 并且薪资大于 8000 的文档
$all 匹配数组中所有元素满足指定条件 db.collection.find({ "tags": { "$all": [ { "$elemMatch": { "tagKey": "color", "tagValue": "red" } }, { "$elemMatch": { "tagKey": "size", "tagValue": "XL" } } ] } }) 查询包含 tagKey 为 “color”,tagValue 为 “red” 的标签,并且包含 tagKey 为 “size”,tagValue 为 “XL” 的标签的文档
$elemMatch 匹配数组中至少一个元素满足指定条件 db.collection.find({ "tags": { "$elemMatch": { "tagKey": "color", "tagValue": "blue" } } }) 查询包含 tagKey 为 “color”,tagValue 包含 “blue” 的标签的文档
$text 全文搜索 db.collection.find({ "$text": { "$search": "searchTerm" } }) 进行全文搜索,查找包含 “searchTerm” 的文档
$type 指定字段类型 db.collection.find({ "field": { "$type": "string" } }) 查询指定字段类型为字符串的文档
$size 数组长度 db.collection.find({ "field": { "$size": sizeValue } }) 查询指定字段数组长度为 sizeValue 的文档
$exists 字段存在 db.collection.find({ "field": { "$exists": true } }) 查询指定字段存在的文档
$mod 取模 db.collection.find({ "field": { "$mod": [divisor, remainder] } }) 查询指定字段取模后符合给定除数和余数的文档

SpringBoot代码示例

  • 操作org.bson.Document对象,无需创建实体映射对象,但操作时需要指定集合名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
package com.hanqf;

import org.bson.Document;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

@SpringBootTest
class BasicTests {

@Autowired
private MongoTemplate mongoTemplate;

/*
// 初始化数据
db.collection.insertMany([
{
"name": "item1",
"age": 20,
"salary": 5000,
"colors": ["red", "blue", "green"],
"sizes": ["S", "M", "L"],
"tags": [
{ "tagKey": "color", "tagValue": "red" },
{ "tagKey": "size", "tagValue": "M" },
{ "tagKey": "style", "tagValue": "casual" }
]
},
{
"name": "item2",
"age": 30,
"salary": 8000,
"colors": ["green", "yellow"],
"sizes": ["M", "L", "XL"],
"tags": [
{ "tagKey": "color", "tagValue": "blue" },
{ "tagKey": "size", "tagValue": "XL" },
{ "tagKey": "style", "tagValue": "formal" }
]
},
{
"name": "item3",
"age": 25,
"salary": 10000,
"colors": ["red", "green"],
"sizes": ["L", "XL"],
"tags": [
{ "tagKey": "color", "tagValue": "green" },
{ "tagKey": "size", "tagValue": "L" },
{ "tagKey": "style", "tagValue": "casual" }
]
}
]);
*/
@Test
void initializeData() {
List<Document> documents = Arrays.asList(
// 文档1
new Document().append("name", "item1")
.append("age", 20)
.append("salary", 5000)
.append("colors", Arrays.asList("red", "blue", "green"))
.append("sizes", Arrays.asList("S", "M", "L"))
.append("tags", Arrays.asList(
new Document().append("tagKey", "color")
.append("tagValue", "red"),
new Document().append("tagKey", "size")
.append("tagValue", "M"),
new Document().append("tagKey", "style")
.append("tagValue", "casual")
)),
// 文档2
new Document().append("name", "item2")
.append("age", 30)
.append("salary", 8000)
.append("colors", Arrays.asList("green", "yellow"))
.append("sizes", Arrays.asList("M", "L", "XL"))
.append("tags", Arrays.asList(
new Document().append("tagKey", "color")
.append("tagValue", "blue"),
new Document().append("tagKey", "size")
.append("tagValue", "XL"),
new Document().append("tagKey", "style")
.append("tagValue", "formal")
)),
// 文档3
new Document().append("name", "item3")
.append("age", 25)
.append("salary", 10000)
.append("colors", Arrays.asList("red", "green"))
.append("sizes", Arrays.asList("L", "XL"))
.append("tags", Arrays.asList(
new Document().append("tagKey", "color")
.append("tagValue", "green"),
new Document().append("tagKey", "size")
.append("tagValue", "L"),
new Document().append("tagKey", "style")
.append("tagValue", "casual")
))
);
// 这里要指定集合名称
mongoTemplate.insert(documents, "collection");
}

/**
* 也可以通过json来构建Document对象
*/
@Test
void initializeData2() {
List<String> jsonList = new ArrayList<>();
jsonList.add("""
{
"name": "item1",
"age": 20,
"salary": 5000,
"colors": ["red", "blue", "green"],
"sizes": ["S", "M", "L"],
"tags": [
{ "tagKey": "color", "tagValue": "red" },
{ "tagKey": "size", "tagValue": "M" },
{ "tagKey": "style", "tagValue": "casual" }
]
}
""");
jsonList.add("""
{
"name": "item2",
"age": 30,
"salary": 8000,
"colors": ["green", "yellow"],
"sizes": ["M", "L", "XL"],
"tags": [
{ "tagKey": "color", "tagValue": "blue" },
{ "tagKey": "size", "tagValue": "XL" },
{ "tagKey": "style", "tagValue": "formal" }
]
}
""");
jsonList.add("""
{
"name": "item3",
"age": 25,
"salary": 10000,
"colors": ["red", "green"],
"sizes": ["L", "XL"],
"tags": [
{ "tagKey": "color", "tagValue": "green" },
{ "tagKey": "size", "tagValue": "L" },
{ "tagKey": "style", "tagValue": "casual" }
]
}
""");

List<Document> documents = new ArrayList<>();
for (String json : jsonList) {
// 通过Document.parse()方法将json字符串转换为Document对象
documents.add(Document.parse(json));
}
mongoTemplate.insert(documents, "collection");
}


@Test
void testQueries() {
QueryExecutor queryExecutor = new QueryExecutor(mongoTemplate);
// db.collection.find({ "age": { "$lt": 25 } })
printResult("findAgeLessThan25", queryExecutor.findAgeLessThan25());
// db.collection.find({ "age": { "$lte": 25 } })
printResult("findAgeLessThanOrEqualTo25", queryExecutor.findAgeLessThanOrEqualTo25());
// db.collection.find({ "age": { "$gt": 25 } })
printResult("findAgeGreaterThan25", queryExecutor.findAgeGreaterThan25());
// db.collection.find({ "age": { "$gte": 25 } })
printResult("findAgeGreaterThanOrEqualTo25", queryExecutor.findAgeGreaterThanOrEqualTo25());
// db.collection.find({ "age": { "$ne": 25 } })
printResult("findAgeNotEqualTo25", queryExecutor.findAgeNotEqualTo25());
// db.collection.find({ "age": { "$in": [20, 25] } })
printResult("findAgeInArray", queryExecutor.findAgeInArray(List.of(20, 25)));
// db.collection.find({ "age": { "$nin": [20, 25] } })
printResult("findAgeNotInArray", queryExecutor.findAgeNotInArray(List.of(20, 25)));
// db.collection.find({ "$or": [ { "age": 20 }, { "salary": { "$gt": 8000 } } ] })
printResult("findAgeOrSalary", queryExecutor.findAgeOrSalary());
// db.collection.find({ "$and": [ { "age": 20 }, { "salary": { "$gt": 8000 } } ] })
printResult("findAgeAndSalary", queryExecutor.findAgeAndSalary());
/*
db.collection.find({ "tags": { "$all": [
{ "$elemMatch": { "tagKey": "color", "tagValue": "red" } },
{ "$elemMatch": { "tagKey": "size", "tagValue": "XL" } }
]}})
*/
printResult("findTagsWithColorAndSize", queryExecutor.findTagsWithColorAndSize());
// db.collection.find({ "tags": { "$elemMatch": { "tagKey": "color", "tagValue": /blue/ } } })
printResult("findTagsWithColorContainingBlue", queryExecutor.findTagsWithColorContainingBlue());
// db.collection.find({ "tags.tagKey": "color" })
printResult("findTagsWithColor", queryExecutor.findTagsWithColor());
// db.collection.find({ "tags": { "$size": 3 } })
printResult("findDocumentWithTagsSizeThree", queryExecutor.findDocumentWithTagsSizeThree());
// db.collection.find({ "tags": { "$elemMatch": { "tagKey": "color", "tagValue": "red" } } })
printResult("findDocumentWithSpecificTag", queryExecutor.findDocumentWithSpecificTag());
/*
db.collection.find({ "tags": { "$all": [
{ "$elemMatch": { "tagKey": "color", "tagValue": /green/ } }
]}})
*/
printResult("findAllElementsWithSpecificTag", queryExecutor.findAllElementsWithSpecificTag());
printResult("findAllElementsWithSpecificTagByJson", queryExecutor.findAllElementsWithSpecificTagByJson());
}

private void printResult(String queryName, List<Document> result) {
System.out.println("Query: " + queryName + " ###################################################");
for (Document document : result) {
System.out.println(document);
}
System.out.println();
}


public static class QueryExecutor {
private final MongoTemplate mongoTemplate;

public QueryExecutor(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}

// 查询年龄小于 25 的文档
// db.collection.find({ "age": { "$lt": 25 } })
public List<Document> findAgeLessThan25() {
Query query = new Query(Criteria.where("age").lt(25));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询年龄小于等于 25 的文档
// db.collection.find({ "age": { "$lte": 25 } })
public List<Document> findAgeLessThanOrEqualTo25() {
Query query = new Query(Criteria.where("age").lte(25));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询年龄大于 25 的文档
// db.collection.find({ "age": { "$gt": 25 } })
public List<Document> findAgeGreaterThan25() {
Query query = new Query(Criteria.where("age").gt(25));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询年龄大于等于 25 的文档
// db.collection.find({ "age": { "$gte": 25 } })
public List<Document> findAgeGreaterThanOrEqualTo25() {
Query query = new Query(Criteria.where("age").gte(25));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询年龄不等于 25 的文档
// db.collection.find({ "age": { "$ne": 25 } })
public List<Document> findAgeNotEqualTo25() {
Query query = new Query(Criteria.where("age").ne(25));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询年龄存在并且在指定数组中的文档
// db.collection.find({ "age": { "$in": [20, 25] } })
public List<Document> findAgeInArray(List<Integer> ages) {
Query query = new Query(Criteria.where("age").in(ages));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询年龄不存在或者不在指定数组中的文档
// db.collection.find({ "age": { "$nin": [20, 25] } })
public List<Document> findAgeNotInArray(List<Integer> ages) {
Query query = new Query(Criteria.where("age").nin(ages));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询年龄存在并且为 20,或者薪资大于 8000 的文档
// db.collection.find({ "$or": [ { "age": 20 }, { "salary": { "$gt": 8000 } } ] })
public List<Document> findAgeOrSalary() {
Query query = new Query(new Criteria().orOperator(Criteria.where("age").is(20), Criteria.where("salary").gt(8000)));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询年龄为 20,并且薪资大于 8000 的文档
// db.collection.find({ "$and": [ { "age": 20 }, { "salary": { "$gt": 8000 } } ] })
public List<Document> findAgeAndSalary() {
Query query = new Query(new Criteria().andOperator(Criteria.where("age").is(20), Criteria.where("salary").gt(8000)));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询包含 tagKey 为 "color",tagValue 为 "red" 的标签,并且包含 tagKey 为 "size",tagValue 为 "XL" 的标签的文档
/*
db.collection.find({ "tags": { "$all": [
{ "$elemMatch": { "tagKey": "color", "tagValue": "red" } },
{ "$elemMatch": { "tagKey": "size", "tagValue": "XL" } }
]}})
*/
public List<Document> findTagsWithColorAndSize() {
Criteria criteria = new Criteria().andOperator(Criteria.where("tags").elemMatch(Criteria.where("tagKey").is("color").and("tagValue").is("red")), Criteria.where("tags").elemMatch(Criteria.where("tagKey").is("size").and("tagValue").is("XL")));
Query query = new Query(criteria);
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询包含 tagKey 为 "color",tagValue 包含 "blue" 的标签的文档
// db.collection.find({ "tags": { "$elemMatch": { "tagKey": "color", "tagValue": /blue/ } } })
public List<Document> findTagsWithColorContainingBlue() {
Query query = new Query(Criteria.where("tags").elemMatch(Criteria.where("tagKey").is("color").and("tagValue").regex("blue")));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}


// 查询包含 tagKey 为 "color" 的标签的文档
// db.collection.find({ "tags.tagKey": "color" })
public List<Document> findTagsWithColor() {
Query query = new Query(Criteria.where("tags.tagKey").is("color"));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询 tags 数组长度为 3 的文档
// db.collection.find({ "tags": { "$size": 3 } })
public List<Document> findDocumentWithTagsSizeThree() {
Query query = new Query(Criteria.where("tags").size(3));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询包含 tagKey 为 "color",tagValue 为 "red" 的标签的文档
// db.collection.find({ "tags": { "$elemMatch": { "tagKey": "color", "tagValue": "red" } } })
public List<Document> findDocumentWithSpecificTag() {
Query query = new Query(Criteria.where("tags").elemMatch(Criteria.where("tagKey").is("color").and("tagValue").is("red")));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询 tags 数组所有元素满足 tagKey 为 "color",tagValue 包含 "green" 的标签的文档
/*
db.collection.find({ "tags": { "$all": [
{ "$elemMatch": { "tagKey": "color", "tagValue": /green/ } }
]}})
*/
public List<Document> findAllElementsWithSpecificTag() {
Query query = new Query(Criteria.where("tags").elemMatch(Criteria.where("tagKey").is("color").and("tagValue").regex("green")));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}

// 查询 tags 数组所有元素满足 tagKey 为 "color",tagValue 包含 "green" 的标签的文档
// 使用 BasicQuery,可以使用 json 字符串,这样就可以直接使用 mongo 的查询语法
public List<Document> findAllElementsWithSpecificTagByJson() {
String json = """
{ "tags": { "$all": [
{ "$elemMatch": { "tagKey": "color", "tagValue": /green/ } }
]}}
""";
Query query = new BasicQuery(json);
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Document.class, "collection");
}
}
}
  • 操作实体类

相关注解 修饰范围 作用 属性
@Document 映射类对象为Mongo文档 value, collection
@Id 成员变量、方法 将成员变量值映射为文档的_id的值
@Field 成员变量、方法 将成员变量及值映射为文档中key:value对 name, value
@Transient 成员变量、方法 指定成员变量不参与文档的序列化
  • 使用 @Document 注解指定集合名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.hanqf.mongo.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "collection")
public class Item {

@Id
private String id;
@Field
private String name;
@Field
private int age;
@Field
private double salary;
@Field
private List<String> colors;
@Field
private List<String> sizes;
@Field
private List<Tag> tags;

public Item(String name, int age, double salary, List<String> colors, List<String> sizes, List<Tag> tags) {
this.name = name;
this.age = age;
this.salary = salary;
this.colors = colors;
this.sizes = sizes;
this.tags = tags;
}




@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Tag {
private String tagKey;
private String tagValue;

}
}
  • 查询示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
package com.hanqf;

import com.hanqf.mongo.model.Item;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.util.Arrays;
import java.util.List;
@SpringBootTest
class BasicTests2 {

@Autowired
private MongoTemplate mongoTemplate;

@Test
void initializeData() {
// Initialize data
List<Item> items = Arrays.asList(
new Item("item1", 20, 5000,
Arrays.asList("red", "blue", "green"),
Arrays.asList("S", "M", "L"),
Arrays.asList(new Item.Tag("color", "red"),
new Item.Tag("size", "M"),
new Item.Tag("style", "casual"))),
new Item("item2", 30, 8000,
Arrays.asList("green", "yellow"),
Arrays.asList("M", "L", "XL"),
Arrays.asList(new Item.Tag("color", "blue"),
new Item.Tag("size", "XL"),
new Item.Tag("style", "formal"))),
new Item("item3", 25, 10000,
Arrays.asList("red", "green"),
Arrays.asList("L", "XL"),
Arrays.asList(new Item.Tag("color", "green"),
new Item.Tag("size", "L"),
new Item.Tag("style", "casual")))
);

mongoTemplate.insertAll(items);
}

@Test
void testQueries() {
BasicTests2.QueryExecutor queryExecutor = new BasicTests2.QueryExecutor(mongoTemplate);
// db.collection.find({ "age": { "$lt": 25 } })
printResult("findAgeLessThan25", queryExecutor.findAgeLessThan25());
// db.collection.find({ "age": { "$lte": 25 } })
printResult("findAgeLessThanOrEqualTo25", queryExecutor.findAgeLessThanOrEqualTo25());
// db.collection.find({ "age": { "$gt": 25 } })
printResult("findAgeGreaterThan25", queryExecutor.findAgeGreaterThan25());
// db.collection.find({ "age": { "$gte": 25 } })
printResult("findAgeGreaterThanOrEqualTo25", queryExecutor.findAgeGreaterThanOrEqualTo25());
// db.collection.find({ "age": { "$ne": 25 } })
printResult("findAgeNotEqualTo25", queryExecutor.findAgeNotEqualTo25());
// db.collection.find({ "age": { "$in": [20, 25] } })
printResult("findAgeInArray", queryExecutor.findAgeInArray(List.of(20, 25)));
// db.collection.find({ "age": { "$nin": [20, 25] } })
printResult("findAgeNotInArray", queryExecutor.findAgeNotInArray(List.of(20, 25)));
// db.collection.find({ "$or": [ { "age": 20 }, { "salary": { "$gt": 8000 } } ] })
printResult("findAgeOrSalary", queryExecutor.findAgeOrSalary());
// db.collection.find({ "$and": [ { "age": 20 }, { "salary": { "$gt": 8000 } } ] })
printResult("findAgeAndSalary", queryExecutor.findAgeAndSalary());
/*
db.collection.find({ "tags": { "$all": [
{ "$elemMatch": { "tagKey": "color", "tagValue": "red" } },
{ "$elemMatch": { "tagKey": "size", "tagValue": "XL" } }
]}})
*/
printResult("findTagsWithColorAndSize", queryExecutor.findTagsWithColorAndSize());
// db.collection.find({ "tags": { "$elemMatch": { "tagKey": "color", "tagValue": /blue/ } } })
printResult("findTagsWithColorContainingBlue", queryExecutor.findTagsWithColorContainingBlue());
// db.collection.find({ "tags.tagKey": "color" })
printResult("findTagsWithColor", queryExecutor.findTagsWithColor());
// db.collection.find({ "tags": { "$size": 3 } })
printResult("findDocumentWithTagsSizeThree", queryExecutor.findDocumentWithTagsSizeThree());
// db.collection.find({ "tags": { "$elemMatch": { "tagKey": "color", "tagValue": "red" } } })
printResult("findDocumentWithSpecificTag", queryExecutor.findDocumentWithSpecificTag());
/*
db.collection.find({ "tags": { "$all": [
{ "$elemMatch": { "tagKey": "color", "tagValue": /green/ } }
]}})
*/
printResult("findAllElementsWithSpecificTag", queryExecutor.findAllElementsWithSpecificTag());
printResult("findAllElementsWithSpecificTagByJson", queryExecutor.findAllElementsWithSpecificTagByJson());
}

private void printResult(String queryName, List<Item> result) {
System.out.println("Query: " + queryName + " ###################################################");
for (Item item : result) {
System.out.println(item);
}
System.out.println();
}


public static class QueryExecutor {
private final MongoTemplate mongoTemplate;

public QueryExecutor(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}

// 查询年龄小于 25 的文档
// db.collection.find({ "age": { "$lt": 25 } })
public List<Item> findAgeLessThan25() {
Query query = new Query(Criteria.where("age").lt(25));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询年龄小于等于 25 的文档
// db.collection.find({ "age": { "$lte": 25 } })
public List<Item> findAgeLessThanOrEqualTo25() {
Query query = new Query(Criteria.where("age").lte(25));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询年龄大于 25 的文档
// db.collection.find({ "age": { "$gt": 25 } })
public List<Item> findAgeGreaterThan25() {
Query query = new Query(Criteria.where("age").gt(25));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询年龄大于等于 25 的文档
// db.collection.find({ "age": { "$gte": 25 } })
public List<Item> findAgeGreaterThanOrEqualTo25() {
Query query = new Query(Criteria.where("age").gte(25));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询年龄不等于 25 的文档
// db.collection.find({ "age": { "$ne": 25 } })
public List<Item> findAgeNotEqualTo25() {
Query query = new Query(Criteria.where("age").ne(25));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询年龄存在并且在指定数组中的文档
// db.collection.find({ "age": { "$in": [20, 25] } })
public List<Item> findAgeInArray(List<Integer> ages) {
Query query = new Query(Criteria.where("age").in(ages));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询年龄不存在或者不在指定数组中的文档
// db.collection.find({ "age": { "$nin": [20, 25] } })
public List<Item> findAgeNotInArray(List<Integer> ages) {
Query query = new Query(Criteria.where("age").nin(ages));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询年龄存在并且为 20,或者薪资大于 8000 的文档
// db.collection.find({ "$or": [ { "age": 20 }, { "salary": { "$gt": 8000 } } ] })
public List<Item> findAgeOrSalary() {
Query query = new Query(new Criteria().orOperator(
Criteria.where("age").is(20),
Criteria.where("salary").gt(8000)
));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询年龄为 20,并且薪资大于 8000 的文档
// db.collection.find({ "$and": [ { "age": 20 }, { "salary": { "$gt": 8000 } } ] })
public List<Item> findAgeAndSalary() {
Query query = new Query(new Criteria().andOperator(
Criteria.where("age").is(20),
Criteria.where("salary").gt(8000)
));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询包含 tagKey 为 "color",tagValue 为 "red" 的标签,并且包含 tagKey 为 "size",tagValue 为 "XL" 的标签的文档
/*
db.collection.find({ "tags": { "$all": [
{ "$elemMatch": { "tagKey": "color", "tagValue": "red" } },
{ "$elemMatch": { "tagKey": "size", "tagValue": "XL" } }
]}})
*/
public List<Item> findTagsWithColorAndSize() {
Criteria criteria = new Criteria().andOperator(
Criteria.where("tags").elemMatch(
Criteria.where("tagKey").is("color").and("tagValue").is("red")
),
Criteria.where("tags").elemMatch(
Criteria.where("tagKey").is("size").and("tagValue").is("XL")
)
);
Query query = new Query(criteria);
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询包含 tagKey 为 "color",tagValue 包含 "blue" 的标签的文档
// db.collection.find({ "tags": { "$elemMatch": { "tagKey": "color", "tagValue": /blue/ } } })
public List<Item> findTagsWithColorContainingBlue() {
Query query = new Query(Criteria.where("tags").elemMatch(
Criteria.where("tagKey").is("color").and("tagValue").regex("blue")
));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}


// 查询包含 tagKey 为 "color" 的标签的文档
// db.collection.find({ "tags.tagKey": "color" })
public List<Item> findTagsWithColor() {
Query query = new Query(Criteria.where("tags.tagKey").is("color"));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询 tags 数组长度为 3 的文档
// db.collection.find({ "tags": { "$size": 3 } })
public List<Item> findDocumentWithTagsSizeThree() {
Query query = new Query(Criteria.where("tags").size(3));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询包含 tagKey 为 "color",tagValue 为 "red" 的标签的文档
// db.collection.find({ "tags": { "$elemMatch": { "tagKey": "color", "tagValue": "red" } } })
public List<Item> findDocumentWithSpecificTag() {
Query query = new Query(Criteria.where("tags").elemMatch(
Criteria.where("tagKey").is("color").and("tagValue").is("red")
));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询 tags 数组所有元素满足 tagKey 为 "color",tagValue 包含 "green" 的标签的文档
/*
db.collection.find({ "tags": { "$all": [
{ "$elemMatch": { "tagKey": "color", "tagValue": /green/ } }
]}})
*/
public List<Item> findAllElementsWithSpecificTag() {
Query query = new Query(Criteria.where("tags").elemMatch(
Criteria.where("tagKey").is("color").and("tagValue").regex("green")
));
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}

// 查询 tags 数组所有元素满足 tagKey 为 "color",tagValue 包含 "green" 的标签的文档
// 使用 BasicQuery,可以使用 json 字符串,这样就可以直接使用 mongo 的查询语法
public List<Item> findAllElementsWithSpecificTagByJson() {
String json = """
{ "tags": { "$all": [
{ "$elemMatch": { "tagKey": "color", "tagValue": /green/ } }
]}}
""";
Query query = new BasicQuery(json);
System.out.println(query); // 打印出生成的查询字符串
return mongoTemplate.find(query, Item.class);
}
}
}

常用的查询方法

  • 查询所有文档

1
2
// db.employee.find()
List<Employee> list = mongoTemplate.findAll(Employee.class);
  • 根据_id查询

1
2
// db.employee.findOne({ "_id": 1 })|
Employee e = mongoTemplate.findById(1, Employee.class);
  • 查询第一个文档

1
2
// db.employee.findOne({})
Employee e = mongoTemplate.findOne(new Query(), Employee.class);
  • 条件查询,排序及分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
db.employee.find({
"$or": [
{ "username": "张三" },
{ "salary": { "$gt": 5000 } }
]
}).sort({ "salary": -1 }).skip(2).limit(4)
*/
Query query = new Query(new Criteria().orOperator(Criteria.where("name").is("张三"), Criteria.where("salary").gt(5000)););

// 如果你不熟悉 Criteria,但是熟悉 mongo 的查询语法,可以使用 BasicQuery
/*
String json = """
{
"$or": [
{ "username": "张三" },
{ "salary": { "$gt": 5000 } }
]
}
""";
Query query = new BasicQuery(json);
*/

//skip limit 分页 skip用于指定跳过记录数,limit则用于限定返回结果数量。
query.with(Sort.by(Sort.Order.desc("salary")))
.skip(2) //指定跳过记录数
.limit(4); //每页显示记录数

//查询结果
List<Employee> employees = mongoTemplate.find(
query, Employee.class);
  • 只返回部分字段

1
2
3
4
5
6
7
8
9
10
11
12
/*
db.employee.find(
{ "age": { "$gte": 18 } }, // 筛选条件,年龄大于等于18岁的文档
{ "name": 1, "age": 1 } // 指定返回的字段,只包含"name"和"age",其中1表示包含该字段,0表示不包含
)
*/
Query query = new Query();
query.addCriteria(Criteria.where("age").gte(18)); // 筛选条件,年龄大于等于18岁的文档
query.fields().include("name", "age").exclude("id");// 指定返回的字段,只包含"name"和"age",要去除id,否则默认会返回id
List<Employee> results = mongoTemplate.find(query, Employee.class);
// Employee(id=null, name=张三, age=21, salary=null, entryDay=null)
results.forEach(System.out::println);
  • 去重

distinct 方法只能直接获取唯一值,并不能在查询过程中进行其他的聚合操作,使用场景非常受限,推荐使用聚合方式进行查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//语法:db.collectionName.distinct("fieldName", { /* 过滤条件 */ }),这将返回指定字段 fieldName 的唯一值数组。
// 示例:db.collection.distinct("name",{age:{$gte:25}})

// 方式1
DistinctIterable<String> distinctIterable = mongoTemplate.getCollection("collection")
.distinct("name", BsonDocument.parse("{age:{$gte:25}}"), String.class);

// 方式2
// DistinctIterable<String> distinctIterable = mongoTemplate.getCollection("collection")
// .distinct("name", new Document("age", new Document("$gte", 25)), String.class);


// 将DistinctIterable转换为List
List<String> distinctNames = new ArrayList<>();
distinctIterable.iterator().forEachRemaining(distinctNames::add);
// 打印输出
distinctNames.forEach(System.out::println);


// 聚合方式,聚合方式的详细说明会在下一篇博客中介绍
/*
db.collection.aggregate([
{
$match: { age: { $gte: 25 } }
},
{
$group: {
_id: "$name"
}
}
])
*/
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("age").gte(25)),
Aggregation.group("name")
);

AggregationResults<Document> results = mongoTemplate.aggregate(aggregation, "collection", Document.class);
List<String> distinctNames = results.getMappedResults().stream()
.map(document -> document.getString("_id"))
.toList();

distinctNames.forEach(System.out::println);

SpringBoot对Mongo的查询,其实就是如何通过Criteria来构建一个Query,所以我们的目标就是要熟练掌握Criteria的语法。当然,如果你熟悉Mongo的查询语法,也可以直接使用BasicQuery来实现Mongo的查询。

插入

  • Mongo语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 插入单个文档
db.collection.insertOne(
<document>,
{
writeConcern: <document>
}
)
# 示例
db.demo.insertOne(
{ name: "张三", age: 35},
{
writeConcern: { w: "majority", j: true, wtimeout: 5000 }
}
)

# 插入多个文档
db.collection.insertMany(
[ <document 1> , <document 2>, ... ],
{
writeConcern: <document>,
ordered: <boolean>
}
)

writeConcern 是 MongoDB 中用来控制写入确认的选项,可选。以下是 writeConcern 参数的一些常见选项:

  • w:指定写入确认级别。如果指定为数字,则表示要等待写入操作完成的节点数。如果指定为 majority,则表示等待大多数节点完成写入操作。默认为 1,表示等待写入操作完成的节点数为 1。

  • j:表示写入操作是否要求持久化到磁盘。如果设置为 true,则表示写入操作必须持久化到磁盘后才返回成功。如果设置为 false,则表示写入操作可能在数据被持久化到磁盘之前返回成功。默认为 false。

  • wtimeout:表示等待写入操作完成的超时时间,单位为毫秒。如果超过指定的时间仍然没有返回确认信息,则返回错误。默认为 0,表示不设置超时时间。

ordered:指定是否按顺序写入,默认 true,按顺序写入。

  • 插入单个文档

1
2
3
4
5
6
7
8
9
10
11
/*
db.employee.insertOne({
"_id": 1,
"username": "小明",
"age": 30,
"salary": 10000.00,
"entryDay": new Date()
})
*/
Employee employee = new Employee(1, "小明", 30, 10000.00, new Date());
mongoTemplate.insert(employee);
  • 插入多个文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
db.employee.insertMany([
{
"_id": 2,
"username": "张三",
"age": 21,
"salary": 5000.00,
"entryDay": new Date()
},
{
"_id": 3,
"username": "李四",
"age": 26,
"salary": 8000.00,
"entryDay": new Date()
},
{
"_id": 4,
"username": "王五",
"age": 22,
"salary": 8000.00,
"entryDay": new Date()
},
{
"_id": 5,
"username": "张龙",
"age": 28,
"salary": 6000.00,
"entryDay": new Date()
},
{
"_id": 6,
"username": "赵虎",
"age": 24,
"salary": 7000.00,
"entryDay": new Date()
},
{
"_id": 7,
"username": "赵六",
"age": 28,
"salary": 12000.00,
"entryDay": new Date()
}
])
*/
List<Employee> list = Arrays.asList(
new Employee(2, "张三", 21, 5000.00, new Date()),
new Employee(3, "李四", 26, 8000.00, new Date()),
new Employee(4, "王五", 22, 8000.00, new Date()),
new Employee(5, "张龙", 28, 6000.00, new Date()),
new Employee(6, "赵虎", 24, 7000.00, new Date()),
new Employee(7, "赵六", 28, 12000.00, new Date()));
//插入多条数据
mongoTemplate.insert(list, Employee.class);
  • id存在时更新,不存在时插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
db.employee.updateOne(
{ "_id": 1 },
{
$set: {
"name": "小明",
"age": 30,
"salary": 10000.00,
"entryDay": ISODate("2024-03-05T00:00:00Z")
}
},
{ upsert: true }
)
*/
Employee employee = new Employee(1, "小明", 30, 10000.00, new Date());
//save方法会根据对象的id是否存在来判断是更新还是插入
mongoTemplate.save(employee);

更新

  • Mongo语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 更新单个或多个文档
db.collection.update[One|Many](
<filter>,
<update>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string> // Available starting in MongoDB 4.2.1
}
)

# findAndModify,只能更新单个文档
db.collection.findAndModify({
query:<filter>,
update:<update>
})
# 示例,该操作会返回符合查询条件的文档数据,并完成对文档的修改
# 将某个book文档的收藏数(favCount)加1
db.books.findAndModify({
query:{_id:ObjectId("6457a39c817728350ec83b9d")},
update:{$inc:{favCount:1}}
})
# 默认情况下,findAndModify会返回修改前的“旧”数据。如果希望返回修改后的数据,则可以指定new选项
db.books.findAndModify({
query:{_id:ObjectId("6457a39c817728350ec83b9d")},
update:{$inc:{favCount:1}},
new: true
})
参数 描述
<filter> 一个筛选器对象,用于指定要更新的文档。
<update> 一个更新操作对象,用于指定如何更新文档。可以使用一些操作符,例如$set、$inc、$unset等,以更新文档中的特定字段。
upsert 一个布尔值,用于指定如果找不到与筛选器匹配的文档时是否应插入一个新文档。如果upsert为true,则会插入一个新文档。默认值为false。
writeConcern 一个文档,用于指定写入操作的安全级别。可以指定写入操作需要到达的节点数或等待写入操作的时间。
collation 一个文档,用于指定用于查询的排序规则。例如,可以通过指定locale属性来指定语言环境,从而实现基于区域设置的排序。
arrayFilters 一个数组,用于指定要更新的数组元素。数组元素是通过使用更新操作符$[]和$来指定的。
hint 一个文档或字符串,用于指定查询使用的索引。该参数仅在MongoDB 4.2.1及以上版本中可用。

更新操作符

操作符 格式 描述
$set { $set: { field: value } } 指定一个键并更新值,若键不存在则创建。
$unset { $unset : { field : 1 } } 删除一个键。
$inc { $inc : { field : value } } 对数值类型进行增减。
$rename { $rename : { old_field_name : new_field_name } } 修改字段名称。
$push { $push : { field : value } } 将数值追加到数组中,若数组不存在则会进行初始化。
$pushAll { $pushAll : { field : value_array } } 追加多个值到一个数组字段内。
$pull { $pull : { field : _value } } 从数组中删除指定的元素。
$addToSet { $addToSet : { field : value } } 添加元素到数组中,具有排重功能。
$pop { $pop : { field : 1 } } 删除数组的第一个或最后一个元素。
  • 只更新满足条件的第一条记录

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
db.employee.updateOne(
{ "salary": { "$gte": 8000 } },
{ "$set": { "salary": 13000 } }
)
*/
Query query = new Query(Criteria.where("salary").gte(8000));
Update update = new Update();
//设置更新属性
update.set("salary", 13000);
UpdateResult updateResult = mongoTemplate.updateFirst(query, update, Employee.class);
//返回修改的记录数
System.out.println(updateResult.getModifiedCount());
  • 更新所有满足条件的记录

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
db.employee.updateMany(
{ "salary": { "$gte": 8000 } },
{ "$set": { "salary": 13000 } }
)
*/
Query query = new Query(Criteria.where("salary").gte(8000));
Update update = new Update();
//设置更新属性
update.set("salary", 13000);
UpdateResult updateResult = mongoTemplate.updateMulti(query, update, Employee.class);
//返回修改的记录数
System.out.println(updateResult.getModifiedCount());
  • 没有符合条件的记录则插入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
db.employee.updateOne(
{ "salary": { "$gte": 8000 } },
{ "$set": { "salary": 13000 }, "$setOnInsert": { "id": 11 } },
{ "upsert": true }
)
*/
Query query = new Query(Criteria.where("salary").gte(8000));
Update update = new Update();
//设置更新属性
update.set("salary", 13000);
update.setOnInsert("id",11); //指定_id,只有没有匹配到时才插入
UpdateResult updateResult = mongoTemplate.upsert(query, update, Employee.class);
//返回修改的记录数
System.out.println(updateResult.getModifiedCount());

替换

  • Mongo语法

1
2
3
4
5
6
7
8
9
10
11
db.collection.replaceOne(
<filter>,
<replacement>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>,
hint: <document|string>
}
)

  • replaceOne操作会首先使用指定的筛选条件来查找匹配的文档,然后用提供的新文档完全替换掉原始文档,也就是说replaceOne是整体替换,而不是修改文档中的某些字段。

参数 描述
<filter> 一个筛选器对象,用于指定要替换的文档。只有与筛选器对象匹配的第一个文档才会被替换。
<replacement> 一个替换文档对象,用于指定用于替换原始文档的新文档。替换文档必须包含所有要在原始文档中修改或替换的字段。
upsert 一个布尔值,表示如果找不到与筛选器匹配的文档时是否应插入一个新文档。如果设置为true,则会插入一个新文档。默认为false。
writeConcern 一个文档,用于指定写入操作的安全级别。可以指定写入操作需要到达的节点数或等待写入操作的时间。
collation 一个文档,用于指定用于查询的排序规则。例如,可以通过指定locale属性来指定语言环境,从而实现基于区域设置的排序。
hint 一个文档或字符串,用于指定查询使用的索引。该参数仅在MongoDB 4.2.1及以上版本中可用
  • 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
db.collection.replaceOne(
{ "name": "John" }, // 筛选条件,匹配name为John的文档
{ // 替换文档,用于替换匹配到的文档
"name": "Peter", // 新的name字段值为Peter
"age": 30 // 新增age字段,值为30
}
)
*/
Query query = new Query(Criteria.where("name").is("John"));
Employee replacement = new Employee();
replacement.setName("Peter");
replacement.setAge(30);
mongoTemplate.findAndReplace(query, replacement);

删除

  • Mongo语法

1
2
3
4
5
6
7
8
# 按条件删除多个文档
db.collection.deleteMany(<filter>)

# 按条件删除单个文档
db.collection.deleteOne(<filter>)

# 先查询后删除,返回查询条件对应的文档,sort是可选项
db.collection.findOneAndDelete(<filter>,{sort:{field:1}})
  • 删除所有文档

1
2
3
4
5
6
// db.employee.deleteMany({})
mongoTemplate.remove(new Query(),Employee.class);

// db.employee.drop()
// 清空数据也可以使用drop方法,但是这样会删除索引
mongoTemplate.dropCollection(Employee.class);
  • 按条件删除文档

1
2
3
// db.employee.deleteMany({ "salary": { "$gte": 10000 } })
Query query = new Query(Criteria.where("salary").gte(10000));
mongoTemplate.remove(query, Employee.class);
  • 删除查询到的第一个文档

1
2
3
4
// db.employee.deleteOne({ "salary": { "$gte": 10000 } })
Query query = new Query(Criteria.where("salary").gte(10000));
query.limit(1);
mongoTemplate.remove(query, Employee.class);

批量操作

  • bulkwrite()方法提供了执行批量插入、更新和删除操作的能力。

  • bulkWrite()支持以下写操作:

    • insertOne
    • updateOne
    • updateMany
    • replaceOne
    • deleteOne
    • deleteMany
  • 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package com.hanqf;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.Arrays;
@SpringBootTest
class BulkWriteTests {
@Autowired
private MongoTemplate mongoTemplate;

/*
db.pizzas.insertMany( [
{ _id: 0, type: "pepperoni", size: "small", price: 4 },
{ _id: 1, type: "cheese", size: "medium", price: 7 },
{ _id: 2, type: "vegan", size: "large", price: 8 }
] )
*/
@Test
void insertManyPizzas() {
mongoTemplate.insertAll(Arrays.asList(
new Pizza(0, "pepperoni", "small", 4),
new Pizza(1, "cheese", "medium", 7),
new Pizza(2, "vegan", "large", 8)
));
}

/*
db.pizzas.bulkWrite( [
{ insertOne: { document: { _id: 3, type: "beef", size: "medium", price: 6 } } },
{ insertOne: { document: { _id: 4, type: "sausage", size: "large", price: 10 } } },
{ updateOne: {
filter: { type: "cheese" },
update: { $set: { price: 8 } }
} },
{ deleteOne: { filter: { type: "pepperoni"} } },
{ replaceOne: {
filter: { type: "vegan" },
replacement: { type: "tofu", size: "small", price: 4 }
} }
] )
*/
@Test
void performBulkWrite() {
BulkOperations bulkOperations = mongoTemplate.bulkOps(BulkOperations.BulkMode.ORDERED, Pizza.class);

bulkOperations.insert(Arrays.asList(
new Pizza(3, "beef", "medium", 6),
new Pizza(4, "sausage", "large", 10)
));

bulkOperations.updateOne(
Query.query(Criteria.where("type").is("cheese")),
new Update().set("price", 8)
);

bulkOperations.remove(
Query.query(Criteria.where("type").is("pepperoni")).limit(1)
);

bulkOperations.replaceOne(
Query.query(Criteria.where("type").is("vegan")),
new Pizza(null, "tofu", "small", 4)
);

bulkOperations.execute();
}

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document("pizza")
private static class Pizza {
@Id
private Integer _id;
private String type;
private String size;
private Integer price;

}
}