本文目的:删除MongoDB列表某项/数组某项
关键命令一: $pull、update.pull
The $pull operator removes from an existing array all instances of a value or values that match a specified condition.
它用于删除数组所匹配的项,如果数组[1,1,2,1] 执行pull 1 后,只剩下[2]
关键命令二: $upset、update.upset
($unset运算符删除特定字段。请考虑以下语法:)
The $unset operator deletes a particular field. Consider the following syntax: copycopied
{ $unset: { <“field1”>: “”, … } }
下面看具体例子----||
.
例一. 删除简单数组元素
/* 1 */
{
"_id" : ObjectId("5ec8c716a0d7734e6c2f16fa"),
"name" : "数据1",
"datas" : [
"AA",
"BB",
"CC"
],
}
/* 2 */
{
"_id" : ObjectId("5ec8c74ca0d7734e6c2f16fb"),
"name" : "数据2",
"datas" : [
"AA",
"DD",
"EE"
],
}
需求一:删除name为数据1的datas数组里面的AA
安排!
执行以下命令
db.getCollection('dateList').updateMany({'name':'数据1'},{'$pull': {'datas':'AA'}})
执行后结果是:数据1的datas的AA已删除
/* 1 */
{
"_id" : ObjectId("5ec8c716a0d7734e6c2f16fa"),
"name" : "数据1",
"datas" : [
"BB",
"CC"
],
}
/* 2 */
{
"_id" : ObjectId("5ec8c74ca0d7734e6c2f16fb"),
"name" : "数据2",
"datas" : [
"AA",
"DD",
"EE"
],
}
需求二:删除所有数据数组datas里面的AA
执行以下命令
db.getCollection('dateList').updateMany({'datas':'AA'},{'$pull': {'datas':'AA'}})
执行后结果是:数组datas里面的AA都已删除
/* 1 */
{
"_id" : ObjectId("5ec8c716a0d7734e6c2f16fa"),
"name" : "数据1",
"datas" : [
"BB",
"CC"
],
}
/* 2 */
{
"_id" : ObjectId("5ec8c74ca0d7734e6c2f16fb"),
"name" : "数据2",
"datas" : [
"DD",
"EE"
],
}
需求三:JAVA实现
/**
* 实体类
*/
public class DateList {
private String id;
private String name;
private List<String> datas;
}
/**
* 删除数组内部项,接口
* @param data 删除项的值
* @return
*/
@RequestMapping(value = "delete/{data}")
@ResponseBody
public Object delete(@PathVariable("data") String data){
// Query query = new Query(Criteria.where("name").is("数据1")); //查询条件:上面需求一形式
Query query = new Query(Criteria.where("datas").is(data)); //查询条件:上面需求二形式
Update update = new Update();//更新设置
update.pull("datas", data);
mongoTemplate.updateMulti(query, update, DateList.class);
return null;
}
.
例二. 删除文档数组元素
{
"_id" : ObjectId("5ec8f2b4a0d77352bc90c929"),
"name" : "数据1",
"datas" : [
{
"time" : "9999",
"counts" : NumberLong(30)
},
{
"time" : "10000",
"counts" : NumberLong(88)
}
],
}
需求一:删除time="9999"的datas项
命令
db.getCollection('dateList').updateMany({},{$pull:{datas:{time:"9999"}}})
或者
db.getCollection('dateList').updateMany({'datas.time':"9999"},{$pull:{datas:{time:"9999"}}})
执行后结果:
{
"_id" : ObjectId("5ec8f2b4a0d77352bc90c929"),
"name" : "数据1",
"datas" : [
{
"time" : "10000",
"counts" : NumberLong(88)
}
],
}
需求二:JAVA实现
/**
* 实体类
*/
public class DateList {
private String id;
private String name;
private List<TimeCount> datas;
}
public class TimeCount {
private String time;
private Long counts;
}
/**
* 删除数组内部项
* @param data
* @return
* @throws Exception
*/
@RequestMapping(value = "delete/{data}")
@ResponseBody
public Object delete(@PathVariable("data") String data) throws Exception {
Query query = new Query(Criteria.where("datas.time").is(data));
Update update = new Update();
Document doc = new Document();
doc.put("time",data);
update.pull("datas",doc);
mongoTemplate.updateMulti(query, update, DateList.class);
return null;
}
我们对比一下,后面这个跟前面不一样的是:
可以dubug看一下,这样操作之后的query和update的值
可以看出,这样是跟mongo的执行命令一致了,所以说不管是什么语言封装,调用驱动的时候都是用相同的命令
.
例三. 删除多层嵌套数组某个文档
例二的升级版,先看看数据格式,数组 datas 里面有数组 counts ,现在删除的是counts 的数据
{
"_id" : ObjectId("5ecde35f3bf8aad5abfe111d"),
"name" : "数据1",
"datas" : [
{
"time" : "9999",
"counts" : [
{
"man" : "张山",
"girl" : "小丽"
},
{
"man" : "李四",
"girl" : "小红"
}
]
},
{
"time" : "10000",
"counts" : [
{
"man" : "王五",
"girl" : "小花"
}
]
}
]
}
需求:删除张山这个文档
先上命令
db.dateList.updateMany({'datas.time':"9999"},{$pull:{'datas.$.counts':{'man':"张山"}}})
结果:
{
"_id" : ObjectId("5ecde35f3bf8aad5abfe111d"),
"name" : "数据1",
"datas" : [
{
"time" : "9999",
"counts" : [
{
"man" : "李四",
"girl" : "小红"
}
]
},
{
"time" : "10000",
"counts" : [
{
"man" : "王五",
"girl" : "小花"
}
]
}
]
}
.
例四. 删除数组里面某个集合的键值
需求一:删除datas里面time="9999"的time这个键值
直接上命令命令
db.dateList.updateMany({'datas.time':"9999"},{$unset:{'datas.$.time':null}})
或
db.dateList.updateMany({'datas.time':"9999"},{$unset:{'datas.$.time':""}})
这里不用 pull 命令,改用upset
用upset来删除指定键值,这刚好满足这个需求
执行结果(源数据跟例二一样)
{
"_id" : ObjectId("5ecd0d2ba0d773837421459a"),
"name" : "数据1",
"datas" : [
{
"counts" : NumberLong(30)
},
{
"time" : "10000",
"counts" : NumberLong(88)
}
],
}
需求二:JAVA实现(实体类跟例二一样)
@RequestMapping(value = "delete/{data}")
@ResponseBody
public Object delete(@PathVariable("data") String data) throws Exception {
Query query = new Query(Criteria.where("datas.time").is(data));
Update update = new Update();
update.unset("datas.$.time");
mongoTemplate.updateMulti(query, update, DateList.class);
return null;
}
最后,总结
本文从删除数组内部的项出发解决几个场景问题
本质是删除文档内嵌数据
不同的是pull是删除内嵌数组项,upset是删除内嵌键值
刚好例四是删除数组里面的键值,将两者完美结合,实际上upset可以删除文档内部任意键值
另外还有个知识点,"$" 字符
在例四中,"$" 字符 代表 下标位置索引, 满足条件的数据下标位置就会传递给 这个 字符。使用的场景就是当操作的对象是数组里面某个符合的项,然后对这些项进行内部操作。
比如
db.dateList.updateMany({'datas.time':"9999"},{$unset:{'datas.$.time':""}})
就是操作 datas数组里面符合条件的项,如下图
正常情况下,需要这样去改变
$unset:{'datas.0.time':""}
也就是说要指定下标,但是当使用场景下标不明确的时候,就需要用$去占位。
完结。
感谢
https://blog.csdn.net/wonder_dog/article/details/82682099
https://docs.mongodb.com/v3.2/reference/operator/update/unset/
https://www.cnblogs.com/yanzhi-1996/articles/11095002.html
https://blog.csdn.net/weixin_30950237/article/details/99468786