6. 数据更新操作 4.3

4.1、函数的基本使用

  • 如果要修改数据最直接的使用函数就是update()函数,但是这个函数的语法要求很麻烦.
    语法: db.collection.update(更新条件, 新的对象数据(更新操作符),upsert, multi)
    |-upsert: 如果要更新的数据不存在,则增加一条新的内容(true为增加, false为不增加)
    |-multi: 表示是否只更新满足条件的第一行记录, 如果设置为false,只更新第一条, 如果设置成true全更新。

范例: 更新存在的数据-将年龄是19岁的任的成绩都更新为100分(此时会返回多条数据)

  • 只更新一条
db.students.update(
   {"age": 19},
   {"$set": {
      {"score": 100}  
   }}, false, false
).pretty()

范例: 更新不存在的数据

db.students.update(
  {"age": 30},
  {"$set": {"name": "不存在"}}
  true,
  false
).pretty()

由于没有年龄是30岁的学生信息, 所以此事相当于进行了数据的创建.

那么除了update() 函数之外, 还提供一个save()函数, 这个函数的功能与更新不存在的内容显示

要查询的数据集如果存在就进行覆盖, 没有就创建一个新的数据集

范例: 使用save()操作

db.students.find({"_id": 'ObjectId("sfsdfsd4fs46fs4f")"}, {"age": 50}).pretty()

由于此时对应的id数据存在了,所以就变成了更新操作(覆盖), 但是如果要保存的数据不存在了(不能保存有"_id"), 那么就变成了增加操作

4.2 修改器

对MongoDB数据库而言, 数据的修改会牵扯到内容的变更、结构的变更,所以在进行MongoDB设计的时候就提供有一系列的修改器的应用, 那么像之前使用"$set"就是一个修改器.

  1. $inc: 主要针对于一个数字字段, 增加某个数字字段的数据内容;
    语法: {"$inc": {"成员": 内容}}

范例: 将所有年龄为19岁的学生成绩一律减少30分>db.students.update({"age": 19}, {"$inc:{"score: -30, age: 1}}).pretty()

2.$set: 进行内容的重新设置
语法: {"$set": {"成员": "新内容"}}

范例: 将年龄是20岁的人的成绩修改为89

db.students.upate({"age": 20}, {"$set": {"score": 89}})

3.$unset: 删除某个成员的内容;
语法: {$unset: {"成员": 1}}

范例: 删除"张三"的年龄与成绩信息

db.studens.update({"name": "张三"}, {"$unset": {"age": 1, "score": 1}})

执行之后指定的成员就消失了

4.$push: 相当于将内容追加到指定的成员之中(基本上是数组);

语法: {"$push": {"filed":value}}

范例: 向"李四" 添加课程信息(此时张三信息下没有course信息)

db.students.update({"name": "李四"}, {"$push": {"course": "语文"}}).pretty()

范例: 向"谷大神 -E"里面的课程追加一个"美术"

db.students.update({"name": "谷大神 - E"}, {"$push": {"course": "美术"}}).pretty()

就是进行数组数据的添加操作使用的, 如果没有数组则进行一个新的数组的创建, 如果有则进行内容的追加.

5. $pushAll: 与"$push"是类似的, 可以一次追加多个内容到数组里面;

语法:{"$pushAll": {filed: value}}

范例: 向"王五"的信息里面添加多个课程内容

db.students.update({"name": "王五", {"$pushAll": {"course": ["美术", "音乐", "素描"]}}})

6.$addToSet: 向数组里面增加一个新的内容, 只有这个内容不存在的时候才会增加.

语法: {"$addToSet": {成员: value}}

db.students.update({"name": "王五"}, {"$addToSet": {"course": "舞蹈"}}).pretty()

此时会判断要增加的内容在数组里面是否已经存在了, 如果不存在则向数组之中追加内容, 如果存在了则不做任何的修改操作.

7.$pop 删除数组内的数据

语法: {""$pop": {成员: 内容}}, 内容如果设置为-1表示删除第一个, 如果是1表示删除最后一个;

范例: 删除王五的第一个课程

db.students.update({"name": "王五"}, {"$pop": {"course": -1}})

范例: 删除王五的最后一个课程

db.students.update({"name": "王五"}, {"$pop": {"course": 1}})

8. $pull: 从数组内删除一个指定内容的数据

语法 {"$pull": {成员: value}}, 进行数据比对的, 如果是此数据则删除;

db.students.update({"name": "王五"}, {"$pull": {"course": "音乐"}}).pretty()

9. $pullAll: 一次性删除多个内容;

语法: {"$pull": {成员: [数据一,数据二,...]}}

范例: 删除 "谷大神 -A"中的三门课程

db.students.update({"name": {"谷大神 -A"}, {"$pullAll": {"course": ["语文", "数学", "英语"]}}})

10.$rename: 为成员名称改名

语法: {"$rename": {旧的成员名称: 新的成员名称}}

db.students.update({"name": "张三"}, {"$rename": {"name": "姓名"}}).pretty()

在整个MongoDB数据库里面, 提供的修改器的支持很到位.

4.4 删除数据

在MongoDB里面数据的删除实际上并不复杂, 只需要使用"remove()"函数就可以了。
但是在这个函数是有两个可选项;
删除条件: 满足条件的数据被删除;
是否只删除一个数据, 如果设置为true或者是1表示只删除一个。

范例: 清空infos集合中的数组

db.infos.remove({})

范例: 删除所有姓名里面带有"谷"的信息, 默认情况下会全部删除.

db.students.remove({"name": /谷/})

范例: 删除姓名带有"高"的信息, 要求只删除一个

db.students.remove({"name": /高/}, ture)

删除操作里面依然需要使用限定查询的相关操作内容

5.游标(重点)

所谓的游标就是指的数据可以一行行的进行操作, 非常类似于ResultSet数据处理.在MongoDB数据库里面对于游标的控制非常的简单, 只需要使用find()函数就可以返回游标了。对于返回的游标如果要想进行操作,是有两个函数:
判断是否有下一行数据: hasNext()
取出当前数据: next()

 var cursor = db.students.find()
 cursor.hasNext()
 cursor.next()

以上是游标的操作形式, 但是实际上不可能这么去用, 因为必须利用循环才能够输出内容。

范例: 编写具体的操作代码

var cursor = db.students.find()
while(cursor.hasNext()) {
   var doc = cursor.next()
   print(doc.name)
}
``

相当于每一个数据都单独拿出来进行逐行的控制. 当游标数据取出来之后,实际上每行数据返回的都是一个Object型的内容, 那么如果需要将数据按照json的形式出现, 则可以使用printjson()函数完成.

var cursor = db.students.find()
while(cursor.hasNext()) {
var doc = cursor.next()
printjson(doc)
}


在所有已知的数据库,只有MongoDB的游标操作是最简单,最直观的.

#### 6.索引(重点 )
唯一索引的主要目的是用在某一个字段上,使该字段的内容不重复.
#### 范例: 创建唯一索引
> db.students.ensureIndex({"name": 1}, {"unique": true});

在name字段上的内容绝对不重复.
#### 范例: 在students.集合里面增加重复的数据.
> db.students.insert({"name": "张三", "sex": "女", "age": 22, "score": 100, "address": "房山区"})

此时除了name字段上的内容之外, 发现所有的数据都不一样,但是由于在name字段上设置了唯一索引, 所以整个程序里面如果增加了重复内容, 那么会出现 以下的错误提示信息:
> E11000 duplicate key error collection: mldn.students index: name_1 dup key: { : \"张三\" }"

唯一索引能够保证指定字段上的数据不重复.

6.2 过期索引
在一些程序站点会出出现若干秒之后信息被删除的情况,例如: 手机信息验证码,那么在MongoDB里面就可以轻松的实现过期索引,但是这个时间往往不怎么准确.
范例: 设置过期索引
> db.phones.ensureIndex({"time" 1}, {expireAfterSeconds: 10})

设置索引在10s后过期.

#### 范例: 在一个phones集合里面设置过期索引.
如果要想实现过期索引, 需要保存一个时间信息;

db.phones.insert({"tel":"110","code":"110","time": new Date()})
db.phones.insert({"tel":"111","code":"111","time": new Date()})
db.phones.insert({"tel":"112","code":"112","time": new Date()})
db.phones.insert({"tel":"113","code":"113","time": new Date()})
db.phones.insert({"tel":"114","code":"114","time": new Date()})

等到10秒之后(永远不会那么准确)所保存的数据就会消失. 这样的特性在进行一些临时数据保存的时候非常有帮助, 最早如果没有MongoDB这种特性, 而只是使用最简单的关系型数据库开发, 那么是非常有帮助的.最早如果没有MongoDB这种特性, 而只是使用最简单的关系型数据库开发, 那么是非常麻烦的.


### 6.3 全文索引
在一些信息管理平台上经常需要进行信息模糊查询, 最早的时候利用了某个字段上实现的模糊查询, 但是这个时候返回的信息并不会很准确, 因为只能够查A字段或者B字段, 而在MongoDB里面实现了非常简单的全文检索
#### 范例: 定义了一个新的集合

db.news.insert({"title": "mldn mldnjava lxh gyh", "content": "gyh"})
db.news.insert({"title": "mldn mldnjava lxh", "content": "java"})
db.news.insert({"title": " gyh", "content": "sfq"})
db.news.insert({"title": "gyh", "content": "gry"})
db.news.insert({"title": "sfq", "content": "gry"})


#### 范例: 设置全文检索
> db.news.ensureIndex({"title": "text","content": "text"})

#### 范例: 实现数据的模糊查询
如果要想表示出全文检索, 则使用 "$text"  判断符, 而要想进行数据的查询则使用 "$search" 运算符

|- 查询指定关键字 : {"$seach":"查询关键字"}
|- 查询多个关键字(或关系): {"$search": "查询关键字 查询关键字  ..."}
|- 查询多个关键字(与关系 ): {"$search": "\"查询关键字\"  \"查询关键字\""}
|- 查询多个关键字(排除某一个): {"$search": "查询关键字 查询关键字... -排除关键字"}

#### 范例: 查询单个内容
> db.news.find({"$text": {"$search": "gry"}})

#### 范例:包含有“gry”与“sfq”的信息
> db.news.find({"$text": {"$search": "gry gyh"}})

#### 范例: 同时包含有'mldn" 与 "lxh"的内容
> db.news.find({"$text": {"$search": "\"mldn\" \"lxh\""}})

#### 范例: 包含有"mldn" , 但是没有"gyh"的内容
但是在进行全文检索操作的时候还可以使用相似度的打分来判断检索成果.

#### 范例: 为结果打分
> db.news.find({"$text": {"$search": "gyh"}}, {"score": {"$meta": "textScore"}})

> db.news.find({"$text": {"$search": "gyh"}}, {"score": {"$meta": "textScore"}}).sort({"score": {"$meta": "textScore"}})

按照打分的成绩进行排列, 实际上就可以实现更加准确的信息搜索.
但是在这里面还有一个小问题, 如果一个集合的字段太多了,那么每一个字段都分别设置全文检索麻烦点, 所以简单一些,可以为所有的字段设置全文检索。
#### 范例: 为所有字段设置全文检索
> db.news.ensureIndex({"$**": "text"})

这是一种最简单的设置全文索引的方式,但是尽可能不要用,一个字: 慢.

### 6.4 地理信息索引
地理信息索引分为两类: 2D平面索引, 另外就是2DSphere球面索引。在2D索引里面基本上能够保存的信息都是坐标, 而且坐标保存的就是经纬度坐标.
#### 范例: 定义一个商铺的集合

db.shop.insert({loc: [10, 10]})
db.shop.insert({loc: [11, 10]})
db.shop.insert({loc: [10, 11]})
db.shop.insert({loc: [12, 15]})
db.shop.insert({loc: [16, 17]})
db.shop.insert({loc: [90, 90]})
db.shop.insert({loc: [120, 130]})

#### 范例: 为shop的机会定义2D索引
> db.shop.ensureIndex({"loc": "2d"})

这个时候shop集合就实现坐标位置的查询了, 而要进行查询有两种查询方式:
"$near"查询, 查询距离某个点最近的坐标点
"$geoWithin"查询: 查询某个形状内的点
#### 范例: 假设我的的坐标是: [11,11]
> db.shop.find({loc: {"$near": [11, 11]}})

但是如果执行了以上的查询,实际上会将数据集合里面的前100个点的信息都返回来了, 可以太远了,设置了一个距离范围- 5个点以内的。
#### 范例: 设置查询距离范围
> db.shop.find({"loc": {"$near": [11, 11], "$maxDistance: 5}})

但是需要注意一点,在2D索引里面虽然最大巨鹿,但是不支持最小距离。
但是也可以设置一个查询的范围,使用"$geoWithin"查询, 而可以设置的范围;
矩行的范围($box): {"$box": [[x1, y1], [x2, y2]]}
圆形范围($center):{"$center" : [[x1,y1],r]};
多边型($polygon):{"$polygon" :[[x1,y1],[x2,y2][x3,y3] , ...]}

#### 范例: 查询矩形
> db.shop.find({loc: {"$geoWithin": {"$box": [[9,9], [11, 11]]}}})

#### 范例: 查询圆形
> db.shop.find({loc: {"$geoWithin": {"$center": [[9,9], [11, 11]]}}})

在MongoDB数据库里面,出来一些支持的操作函数之外, 还有一个重要的命令: runCommand(),这个函数可以执行所有的特定的MongoDB命令.
#### 范例: 利用runCommand()实现信息查询.
> db.runCommand({"geoNear": "shop", near: [10, 10], maxDistance: 5, num: 2})

这类的命令可以说是MongoDB之中最为基础的命令.

你可能感兴趣的:(6. 数据更新操作 4.3)