MongoDB 更新/删除文档(四)_java

第一部分 更新文档

文档存入数据库之后,就可以采用Update来修改它的内容,

db.collection.update(
#查询条件
   <query>,
#修改器
   <update>,
   {     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)

参数说明:

query : update的查询条件,类似sql update查询内where后面的。
update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
writeConcern :可选,抛出异常的级别。

1.1 创建与删除($set与$unset)

$set 用来指定一个键的值,如果这个键不存在就创建,否则就更新.

> db.users.find().pretty()
{    "_id" : ObjectId("58bfb2c61b0dbd8a36332275"),    "name" : "Mongodb",    "time" : 15,
}
> db.users.update({"name":"Mongodb"}, {"$set": {"Other": "Nodejs"}})
> 
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.find().pretty()
{    "_id" : ObjectId("58bfb2c61b0dbd8a36332275"),    "name" : "Mongodb",    "time" : 15,    "Other" : "Nodejs"}

添加一个新的字段没有问题, 那么添加一个数组呢?? (当然添加字典也是没问题的,不在此演示)

> db.users.update({"name":"Mongodb"}, {"$set": {"Other": ["Mariadb", "Python"]}})
> db.users.find().pretty()
{    "_id" : ObjectId("58bfb2c61b0dbd8a36332275"),    "name" : "Mongodb",    "time" : 15,    "Other" : [        "Mariadb",        "Python"
    ]
}

删除某个字段---$unset

> db.users.update({"name":"Mongodb"}, {"$unset": {"Other": 1}})

1.2 专职数字($inc)

$inc [increase: 增加] 修改器用来增加已有的键的值,不存在则创建; 只能来增加或减少数字值, 数值可以设置为正负来增加或减少, 仅此用于整数/长整数/双进度浮点数

> db.users.update({"name": "Mongodb"}, {"$inc": {"time": 100}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.find()
{ "_id" : ObjectId("58bfb2c61b0dbd8a36332275"), "name" : "Mongodb", "time" : 115 }

1.3 数组修改器($push)

如果在之前的数据中添加一个新的科目, 并且存储一个数组中就可以采用**$push**, 之前的$set直接覆盖,那么$push是否会存在这种情况?

> db.users.update({"name": "Mongodb"}, {"$push": {"courses": {"name": "Nodejs", "credit": 10}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.update({"name": "Mongodb"}, {"$push": {"courses": {"name": "Mariadb", "credit": 8}}})

结果

> db.users.find().pretty()
{    "_id" : ObjectId("58bfb2c61b0dbd8a36332275"),    "name" : "Mongodb",    "time" : 15,    "courses" : [
        {            "name" : "Nodejs",            "credit" : 10
        },
        {            "name" : "MariaDB",            "credit" : 8
        }
    ]
}

以上的做法实现了, 向数组中添加元素(不是替换), 但是问题是加入我不希望重复添加相同的数据$push 就不能胜任了接下来实现我们需求的就是 $addToSet

1.4 $addToSet 添加

不重复的将元素添加到集合中--$addTOSet

> db.users.update({"name": "Mongodb"}, {"$addToSet": {"courses": {"name": "Nodejs", "credit": 10}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
> db.users.find().pretty()
{    "_id" : ObjectId("58bfb2c61b0dbd8a36332275"),    "name" : "Mongodb",    "time" : 15,    "courses" : [
        {            "name" : "Nodejs",            "credit" : 10
        },
        {            "name" : "Nodejs",            "credit" : 10
        }
    ]
}

$push 与 $addToSet的异同点:

同:
1. 同样可以向集合中添加数据, 字典数组;

不同:
1. $push可以插入同样的数据,结果同时存在
2. $addToSet会覆盖同样的数据

我们在添加一个属性----评价(evaluate)这个数组, 并将一个数组遍历的存入数据库

我们就可以采用$each与$addToSet结合使用

> db.users.update({"name": "Mongodb"},
 {"$addToSet": {"evaluate": {"$each": ["good", "great", "nice"]}}})

结果如下

> db.users.find().pretty()
{    "_id" : ObjectId("58bfb2c61b0dbd8a36332275"),    "name" : "Mongodb",    "time" : 15,    "courses" : [
        ...
    ],    "evaluate" : [        "good",        "great",        "nice"
    ]
}

1.5 操作数组(删除$pop/$pull)

数组是无序的,如何删除特定的元素----第一个? 最后一个? 匹配的某一些?
如何达到所需要求,Mongodb给出了相应的关键字---$pop $pull

原先添加一些测试数据

> db.users.update({"name": "Mongodb"}, {"$push": {"evaluate": {"$each": ["good1", "good2", "nice1", "nice2"]}}})
> 
....    "evaluate" : [        "good",        "great",        "good1",        "good2",        "nice1",        "nice2"
    ]
1.5.1 $pop 删除首尾数据
#最后一个> db.users.update({"name": "Mongodb"}, {"$pop": {"evaluate": 1}})#第一个> db.users.update({"name": "Mongodb"}, {"$pop": {"evaluate": -1}})

脑洞大开的话, 可以试试别的数字 -_-

1.5.2 $pull 删除匹配数据
> db.users.update({"name": "Mongodb"}, {"$pull": {"evaluate": "great"}})

在此会删除匹配的数据, 参数项不可为数组

1.5.2 操作指定位置的数组元素---$

源数据如下, 需求: 更改课程(courses)中,Nodejs的学分(credit)为99

> db.users.find().pretty()
{    "_id" : ObjectId("58bfb2c61b0dbd8a36332275"),    "name" : "Mongodb",    "time" : 15,    "courses" : [
        {            "name" : "Nodejs",            "credit" : 10
        },
        {            "name" : "Mariadb",            "credit" : 10
        }
    ],
    ...
}

提示: 数组下标是从0开始,并且数组名与对象key都有了

第一种: 依据数据下标, 结合$set, 拆找到指定元素就更改. 缺点: 前提是需要知道位置;
第二种使用MongoDB的关键字--$进行匹配, 注意:只可以更改第一个匹配的数据.

实例如下:

> db.users.update({"name": "Mongodb"}, {"$set": {"courses.0.credit": 100}} )
> db.users.update({"name": "Mongodb"}, {"$set": {"courses.$.credit": 100}} )

WriteResult({    "nMatched" : 0,    "nUpserted" : 0,    "nModified" : 0,    "writeError" : {        "code" : 16837,        "errmsg" : "The positional operator did not find the match needed from the query. Unexpanded update: courses.$.credit"
    }
})

比着葫芦画瓢但是报错了!!!!
主要原因是update的查询条件返回的不是数组, 所以无法匹配更改

正确的做法为

#在此你会发现,查找项多了两个参数> db.users.update({"name" : "Mongodb","courses.name": "Nodejs"}, {"$set": {"courses.$.credit": 22}})

> db.users.find().pretty()
{    "_id" : ObjectId("58bfb2c61b0dbd8a36332275"),    "name" : "Mongodb",    "time" : 15,    "courses" : [
        {            "name" : "Nodejs",            "credit" : 22
        },
        {            "name" : "MariaDB",            "credit" : 10
        }
    ],
    ....
}
1.5.3 $pushAll添加所有项目
{ $pushAll: { <field>: [ <value1>, <value2>, ... ] } }
{ $push: { <field>: { $each: [ <value1>, <value2> ... ] } } }
> db.users.update({}, {"$pushAll": {"test": [1, 2, 3, 4, 2, 1, 3]}})
> db.users.find().pretty()
{    "_id" : ObjectId("58ca3706250b163ff8331604"),
    .......    "test" : [1,2,3,4,2,1,3]
}
1.5.4 $pullAll删除所有匹配项
{ $pullAll: { <field1>: [ <value1>, <value2> ... ], ... } }
> db.users.update({}, {"$pullAll": {"test": [1, 2]}})
> db.users.find().pretty()
{    "_id" : ObjectId("58ca3706250b163ff8331604"),    "name" : "Mongodb",
    ......  "test" : [
        3,
        4,
        3
    ]
}
1.5.5 $each与$addToSet/$push结合使用
    { $addToSet: { <field>: { $each: [ <value1>, <value2> ... ] } } }
    
    { $push: { <field>: { $each: [ <value1>, <value2> ... ] } } }
1.5.6 $slice
稍后更新
1.5.7 $sort
稍后更新
1.6 第三个参数---upsert

upsert : 如果不存在update的记录,true为插入,默认是false,不插入。(update+insert)

#在执行之前,只有一条数据,不存在{"name": "Nodejs"}> db.users.update({"name": "Nodejs"}, {"$set": {"time": 10}})#因为没有设置upsert, 没有匹配上,所以都是0WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })#设置upsert为TRUE, 即成功> db.users.update({"name": "Nodejs"}, {"$set": {"time": 10}}, true)
WriteResult({    "nMatched" : 0,    "nUpserted" : 1,    "nModified" : 0,    "_id" : ObjectId("58ca96b56d72019e69b70823")
})

如果再次执行下边的代码, 会在time基础之上+10

> db.users.update({"name": "Nodejs"}, {"$set": {"time": 10}}, true)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
1.7 第四个参数---multi

之前的操作都是基于一个的操作,只匹配第一个,但是假如需要匹配多项, 那么就需要设置multi 参数为 true。

更新第一个credit, 如果存在在基础上加1, 否则创建该字段

> db.users.update({"name": "Mongodb"}, {"$inc": {"courses.0.credit": 1}}, true)
> db.users.update({"courses.name": "Nodejs"}, {"$inc": {"courses.$.credit": 10}}, true)
>

添加一个新的数据

db.users.insert({"name": "Mongodb"})

现在有两条数据, name都为Mongodb, 为每个name=Mongodb的数据添加一个字段为: "teacher: hhw".

> db.users.update({"name": "Mongodb"}, {"$set": {"teacher": "hhw"}}, false, true)

> db.users.find().pretty()
{    "_id" : ObjectId("58c0f8141b0dbd8a364264b8"),    "name" : "Mongodb",    "teacher" : "hhw"}
{    "_id" : ObjectId("58c0f8421b0dbd8a364264b9"),    "name" : "Mongodb",    "time" : 10,    "courses" : [
       ...
    ],    "evaluate" : [
        ...
    ],    "teacher" : "hhw"}

第二部分 删除文档

2.1 remove

只会删除集合users的文档,但是不会删除集合本身,原有的索引也会存在, 但是数据删除时永久性的, 不能撤销.

> db.users.remove();

2.2 deleteOne/deleteMany

db.collection.deleteOne()db.collection.deleteMany()

删除速度更快的可以采用drop_collections("users"), 速度很快但是,集合与索引都删除了.