【DB系列】MongoDB之修改基本使用姿势

文章目录
  1. I. 基本使用
    1. 1. 基本类型修改
      1. a. 基本使用姿势
      2. b. 数字增加/减少
      3. c. 数字比较修改
      4. d. 乘法
      5. e. 日期修改
    2. 2. field修改
      1. a. 重命名
      2. b. 新增成员
      3. c. 删除成员
    3. 3. 数组操作
      1. a. 添加到数组中
      2. b. 批量添加
      3. c. 删除
      4. d. 修改
    4. 4. document操作
      1. a. 添加
      2. c. 修改
      3. d. 删除
  2. II. 其他
    1. 0. 项目
    2. 1. 一灰灰Blog
    3. 2. 声明
    4. 3. 扫描关注

本篇依然是MongoDB curd中的一篇,主要介绍document的更新,主要内容如下

  • 常见类型成员的修改
  • 数组类型成员的增删改
  • document类型成员的增删改

I. 基本使用

首先是准备好基本环境,可以参考博文

在开始之前,先封装一个输出方法,用于打印修改后的record对象

1
2
3
4
5
6
private void queryAndPrint(Query query, String tag) {
System.out.println("------------- after " + tag + " age -------------");
Map record = mongoTemplate.findOne(query, Map.class, COLLECTION_NAME);
System.out.println("query records: " + record);
System.out.println("------------- end " + tag + " age --------------\n");
}

1. 基本类型修改

mongodb支持我们常见的各种基本类型,而MongoTemplate也封装了不少对应的修改方法,最基础的修改,主要是借助Update来实现

常见的使用姿势如:

a. 基本使用姿势

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
public void basicUpdate() {
/*
* {
* "_id" : ObjectId("5c49b07ce6652f7e1add1ea2"),
* "age" : 100,
* "name" : "一灰灰blog",
* "desc" : "Java Developer",
* "add" : [
* "额外增加"
* ],
* "date" : ISODate("2019-01-28T08:00:08.373Z"),
* "doc" : {
* "key" : "小目标",
* "value" : "升职加薪,迎娶白富美"
* }
* }
*/

// 1. 直接修改值的内容
Query query = new Query(Criteria.where("_id").is("5c49b07ce6652f7e1add1ea2"));

Update update = new Update().set("desc", "Java & Python Developer");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
queryAndPrint(query, "set");
}

输出结果为:

1
2
3
------------- after set age -------------
query records: {_id=5c49b07ce6652f7e1add1ea2, age=100, name=一灰灰blog, desc=Java & Python Developer, add=[额外增加], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}}
------------- end set age --------------

b. 数字增加/减少

数字类型修改,使用 org.springframework.data.mongodb.core.query.Update#inc

1
2
3
4
// 数字修改,实现添加or减少
Update numUp = new Update().inc("age", 20L);
mongoTemplate.updateFirst(query, numUp, COLLECTION_NAME);
queryAndPrint(query, "inc");

输出结果为:

1
2
3
------------- after inc age -------------
query records: {_id=5c49b07ce6652f7e1add1ea2, age=120, name=一灰灰blog, desc=Java & Python Developer, add=[额外增加], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}}
------------- end inc age --------------

c. 数字比较修改

数字简单比较之后修改,如org.springframework.data.mongodb.core.query.Update#max

1
2
3
4
// 数字比较修改
Update cmpUp = new Update().max("age", 88);
mongoTemplate.updateFirst(query, cmpUp, COLLECTION_NAME);
queryAndPrint(query, "cmp");

输出结果

1
2
3
------------- after cmp age -------------
query records: {_id=5c49b07ce6652f7e1add1ea2, age=120, name=一灰灰blog, desc=Java & Python Developer, add=[额外增加], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}}
------------- end cmp age --------------

d. 乘法

乘法运算, 主要使用 org.springframework.data.mongodb.core.query.Update#multiply

1
2
3
4
// 乘法
Update mulUp = new Update().multiply("age", 3);
mongoTemplate.updateFirst(query, mulUp, COLLECTION_NAME);
queryAndPrint(query, "multiply");

输出结果

1
2
3
------------- after multiply age -------------
query records: {_id=5c49b07ce6652f7e1add1ea2, age=360.0, name=一灰灰blog, desc=Java & Python Developer, add=[额外增加], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}}
------------- end multiply age --------------

e. 日期修改

日期修改, 如 org.springframework.data.mongodb.core.query.Update#currentDate

1
2
3
4
// 日期修改
Update dateUp = new Update().currentDate("date");
mongoTemplate.updateFirst(query, dateUp, COLLECTION_NAME);
queryAndPrint(query, "date");

输出结果

1
2
3
------------- after date age -------------
query records: {_id=5c49b07ce6652f7e1add1ea2, age=360.0, name=一灰灰blog, desc=Java & Python Developer, add=[额外增加], date=Mon Feb 18 19:34:56 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}}
------------- end date age --------------

2. field修改

不同于mysql的列表是固定的,mongodb的field可以增加、删除和重命名,下面分别看下三种case如何使用

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
/**
* 修改字段名,新增字段,删除字段
*/
public void fieldUpdate() {
/**
* {
* "_id" : ObjectId("5c6a7ada10ffc647d301dd62"),
* "age" : 28.0,
* "name" : "一灰灰blog",
* "desc" : "Java Developer",
* "add" : [
* "额外增加"
* ],
* "date" : ISODate("2019-01-28T08:00:08.373Z"),
* "doc" : {
* "key" : "小目标",
* "value" : "升职加薪,迎娶白富美"
* }
* }
*/
Query query = new Query(Criteria.where("_id").is("5c6a7ada10ffc647d301dd62"));
renameFiled(query);

addField(query);
delField(query);
}

a. 重命名

利用org.springframework.data.mongodb.core.query.Update#rename来实现重命名,需要注意的是,当修改的docuemnt没有这个成员时,相当于没有任务操作

1
2
3
4
5
6
7
8
9
10
11
private void renameFiled(Query query) {
Update update = new Update().rename("desc", "skill");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);

queryAndPrint(query, "rename");

// 如果字段不存在,相当于没有更新
update = new Update().rename("desc", "s-skill");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
queryAndPrint(query, "rename Not exists!");
}

输出结果如下,后面一个语句相当于没有执行

1
2
3
4
5
6
7
------------- after rename age -------------
query records: {_id=5c6a7ada10ffc647d301dd62, age=28.0, name=一灰灰blog, add=[额外增加], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}, skill=Java Developer}
------------- end rename age --------------

------------- after rename Not exists! age -------------
query records: {_id=5c6a7ada10ffc647d301dd62, age=28.0, name=一灰灰blog, add=[额外增加], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}, skill=Java Developer}
------------- end rename Not exists! age --------------

b. 新增成员

新增也是直接利用的Update#set方法,当存在时,修改;不存在时,添加

  • 另外提一下setOnInsert, 如果要更新的文档存在那么$setOnInsert操作符不做任何处理;
1
2
3
4
5
6
7
8
9
10
11
private void addField(Query query) {
// 新增一个字段
// 直接使用set即可
Update update = new Update().set("new-skill", "Python");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);

queryAndPrint(query, "addField");

// 当更新一个不存在的文档时,可以使用setOnInsert
// 如果要更新的文档存在那么$setOnInsert操作符不做任何处理;
}

输出结果如下:

1
2
3
------------- after addField age -------------
query records: {_id=5c6a7ada10ffc647d301dd62, age=28.0, name=一灰灰blog, add=[额外增加], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}, skill=Java Developer, new-skill=Python}
------------- end addField age --------------

c. 删除成员

删除document中的某个成员,借助org.springframework.data.mongodb.core.query.Update#unset, 正好与添加对上

1
2
3
4
5
6
7
private void delField(Query query) {
// 删除字段,如果不存在,则不操作
Update update = new Update().unset("new-skill");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);

queryAndPrint(query, "delField");
}

输出结果如下

1
2
3
------------- after delField age -------------
query records: {_id=5c6a7ada10ffc647d301dd62, age=28.0, name=一灰灰blog, add=[额外增加], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}, skill=Java Developer}
------------- end delField age --------------

3. 数组操作

在MongoDB的document中,有两个有意思的类型,一个是数组,一个是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
/**
* 更新文档中字段为数组成员的值
*/
public void updateInnerArray() {
/**
* {
* "_id" : ObjectId("5c6a7ada10ffc647d301dd62"),
* "age" : 28.0,
* "name" : "一灰灰blog",
* "skill" : "Java Developer",
* "add" : [
* "额外增加"
* ],
* "date" : ISODate("2019-01-28T08:00:08.373Z"),
* "doc" : {
* "key" : "小目标",
* "value" : "升职加薪,迎娶白富美"
* }
* }
*/
Query query = new Query(Criteria.where("_id").is("5c6a7ada10ffc647d301dd62"));
this.addData2Array(query);
this.batchAddData2Array(query);
this.delArrayData(query);
this.updateArrayData(query);
}

a. 添加到数组中

在数组中新增一个数据,提供了两种方式,一个是org.springframework.data.mongodb.core.query.Update#addToSet(java.lang.String, java.lang.Object),一个是org.springframework.data.mongodb.core.query.Update#push(java.lang.String, java.lang.Object);两个的区别在于前者不能插入重复数据,后者可以

1
2
3
4
5
6
7
8
9
10
11
12
private void addData2Array(Query query) {
// 新加一个元素到数组,如果已经存在,则不会加入
String insert = "新添加>>" + System.currentTimeMillis();
Update update = new Update().addToSet("add", insert);
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
queryAndPrint(query, "add2List");

// push 新增元素,允许出现重复的数据
update = new Update().push("add", 10);
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
queryAndPrint(query, "push2List");
}

输出结果

1
2
3
4
5
6
7
------------- after add2List age -------------
query records: {_id=5c6a7ada10ffc647d301dd62, age=28.0, name=一灰灰blog, add=[额外增加, 新添加>>1550489696892], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}, skill=Java Developer}
------------- end add2List age --------------

------------- after push2List age -------------
query records: {_id=5c6a7ada10ffc647d301dd62, age=28.0, name=一灰灰blog, add=[额外增加, 新添加>>1550489696892, 10], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}, skill=Java Developer}
------------- end push2List age --------------

b. 批量添加

一次添加多个,借助addToSeteach来实现

1
2
3
4
5
6
private void batchAddData2Array(Query query) {
// 批量插入数据到数组中, 注意不会将重复的数据丢入mongo数组中
Update update = new Update().addToSet("add").each("2", "2", "3");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
queryAndPrint(query, "batchAdd2List");
}

输出结果:

1
2
3
------------- after batchAdd2List age -------------
query records: {_id=5c6a7ada10ffc647d301dd62, age=28.0, name=一灰灰blog, add=[额外增加, 新添加>>1550489696892, 10, 2, 3], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}, skill=Java Developer}
------------- end batchAdd2List age --------------

c. 删除

借助pull来精确删除某个值

1
2
3
4
5
6
private void delArrayData(Query query) {
// 删除数组中元素
Update update = new Update().pull("add", "2");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
queryAndPrint(query, "delArrayData");
}

输出如下,注意对比,2没有了

1
2
3
------------- after delArrayData age -------------
query records: {_id=5c6a7ada10ffc647d301dd62, age=28.0, name=一灰灰blog, add=[额外增加, 新添加>>1550489696892, 10, 3], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}, skill=Java Developer}
------------- end delArrayData age --------------

d. 修改

修改,首先的问题是要定位,确定删除数组中某个下标的元素,这里借助了一个有意思的站位

  • 定位删除的数组元素方法: arrayKey.index
    • arrayKey 是数组在docment中的名
    • index 表示要删除的索引

一个实例如下

1
2
3
4
5
6
7
8
9
10
11
private void updateArrayData(Query query) {
// 使用set,field.index 来更新数组中的值
// 更新数组中的元素,如果元素存在,则直接更新;如果数组个数小于待更新的索引位置,则前面补null
Update update = new Update().set("add.1", "updateField");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
queryAndPrint(query, "updateListData");

update = new Update().set("add.10", "nullBefore");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
queryAndPrint(query, "updateListData");
}

输出结果,注意后面的,如果数组个数小于待更新的索引位置,则前面补null

1
2
3
4
5
6
7
------------- after updateListData age -------------
query records: {_id=5c6a7ada10ffc647d301dd62, age=28.0, name=一灰灰blog, add=[额外增加, updateField, 10, 3], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}, skill=Java Developer}
------------- end updateListData age --------------

------------- after updateListData age -------------
query records: {_id=5c6a7ada10ffc647d301dd62, age=28.0, name=一灰灰blog, add=[额外增加, updateField, 10, 3, null, null, null, null, null, null, nullBefore], date=Mon Jan 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}, skill=Java Developer}
------------- end updateListData age --------------

4. document操作

内嵌文档,可以所是MongoDB的一个特色了,我们则来看下如何进行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 更新文档中字段为document类型的值
*/
public void updateInnerDoc() {
/**
* {
* "_id" : ObjectId("5c6a956b10ffc647d301dd63"),
* "age" : 18.0,
* "name" : "一灰灰blog",
* "date" : ISODate("2019-02-28T08:00:08.373Z"),
* "doc" : {
* "key" : "小目标",
* "value" : "升职加薪,迎娶白富美"
* },
* "skill" : "Java Developer"
* }
*/

Query query = new Query(Criteria.where("_id").is("5c6a956b10ffc647d301dd63"));
this.addFieldToDoc(query);
this.updateFieldOfDoc(query);
this.delFieldOfDoc(query);
}

a. 添加

借助前面的站位思想,就很好实现了,定位元素的方式采用

  • docName.fieldName
    • docName 为内嵌文档在docunent中的fieldName
    • fieldName 为内嵌文档内部需要修改的fieldName
1
2
3
4
5
6
private void addFieldToDoc(Query query) {
// 内嵌doc新增field
Update update = new Update().set("doc.title", "好好学习,天天向上!");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
queryAndPrint(query, "addFieldToDoc");
}

输出如下

1
2
3
------------- after addFieldToDoc age -------------
query records: {_id=5c6a956b10ffc647d301dd63, age=18.0, name=一灰灰blog, date=Thu Feb 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美, title=好好学习,天天向上!}, skill=Java Developer}
------------- end addFieldToDoc age --------------

c. 修改

1
2
3
4
5
6
private void updateFieldOfDoc(Query query) {
// 内嵌doc修改field
Update update = new Update().set("doc.title", "新的标题:一灰灰Blog!");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
queryAndPrint(query, "updateFieldOfDoc");
}

输出如下

1
2
3
------------- after updateFieldOfDoc age -------------
query records: {_id=5c6a956b10ffc647d301dd63, age=18.0, name=一灰灰blog, date=Thu Feb 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美, title=新的标题:一灰灰Blog!}, skill=Java Developer}
------------- end updateFieldOfDoc age --------------

d. 删除

1
2
3
4
5
6
private void delFieldOfDoc(Query query) {
// 删除内嵌doc中的field
Update update = new Update().unset("doc.title");
mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
queryAndPrint(query, "delFieldOfDoc");
}

输出如下

1
2
3
------------- after delFieldOfDoc age -------------
query records: {_id=5c6a956b10ffc647d301dd63, age=18.0, name=一灰灰blog, date=Thu Feb 28 16:00:08 CST 2019, doc={key=小目标, value=升职加薪,迎娶白富美}, skill=Java Developer}
------------- end delFieldOfDoc age --------------

II. 其他

0. 项目

1. 一灰灰Blog

一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

2. 声明

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

3. 扫描关注

一灰灰blog

QrCode

知识星球

goals


打赏 如果觉得我的文章对您有帮助,请随意打赏。
分享到