mongoDB权威指南总结

创建更新删除文档

  • 插入 insert 批量插入 batchInsert

db.foo.batchInsert([{"_id":1},{"_id":2},{"_id":3}])

  • 删除文档 remove 删除整个集合 drop

db.mailing.list.remove({"opt-out":true}) 删除mailing.list集合中所有”opt-out”为true的信息

使用修改器

$inc $set $unset $push $addToSet $pop $pull

update(Query,Update,is_upsert,is_more) 完整参数

  • Query用来定位需要修改的文档
  • Update需要修改的内容
  • is_upsert 如果不存在是否需要创建新的文档
  • is_more 是否更新多个满足条件的文档

$inc用来增加某一个访问的值,可以当作计数器来使用

1
`db.update({"url":"www.qq.com"},{"$inc":{"pageviews":2}})`  每次update匹配到该url,对应的pageviews属性值便会+2

$set用来操作字段,如果有key则覆盖value,如果没有key则创建key

$unset可以将这个键完全删除

$push用来操作数组,会向已有的数组末尾加入一个元素,要是没有就创建一个新的数组

$push+$each可以实现一次性添加多个值

$push+$each+$slice保证数组的固定长度,$slice必须和$each配合

1
2
3
4
5
6
7
8
9
10
db.movie.update(
{"aaa" : "ddd"},
{"$push" : {
"top10" : {
"$each" : ["111","222","333"],
"$slice" : -10
}
}
}
)

这个数组包含最后加入的10个元素,$slice值必须是整数(负整数即为末尾几个数,正整数即为开头几个数)

$addToSet保证数组内元素不会重复,避免重复插入

$addToSet+$each可以添加多个不同的值

$pop可以从数组任何一端去删除数据 ,注意只能删除一个

1
2
db.blog.update({"_id":ObjectId("6108bb4b28821636220bb519")},{"$pop":{"key":1}}) ## 从末尾删除一个数据
db.blog.update({"_id":ObjectId("6108bb4b28821636220bb519")},{"$pop":{"key":-1}}) ## 从开头删除一个数据

$pull会将所有匹配到的文档删除

定位操作符$,在一个数组当中,当你不知道数组的下标时,可以用定位操作符代替未知的下标

1
2
## 注意的是定位操作符只能使用一次
db.blog.update({"_id":212},{"$set":{"comments.$.author":"ymt"}})

upsert

有则更新无则创建,update()方法第三个可选参数

db.blog.update({“_id”:ObjectId(“6108bb4b28821636220bb519”)},{“$pop”:{“top10”:-1}},true)

如果需要更新所有能够匹配条件的文档,则第四个参数也设置为true

返回被更新的文档

findAndModify命令可以返回更新之后的文档,下面就是一个每次返回id+1的逻辑实现方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component
public class MongoAutoidUtil {
@Autowired
MongoTemplate mongo;

public Integer getNextSequence(String collectionName) {
MongoSequence seq = mongo.findAndModify(query(where("_id").is(collectionName)),
new Update().inc("seq", 1),
options().upsert(true).returnNew(true),
MongoSequence.class);
return seq.getSeq();
}
@Data
public class MongoSequence {
@Id
private String id;
private int seq;
}
}

查询

  • 指定返回哪些键
1
2
## 返回top10这个键,不返回_id键
db.blog.find({"boys.name":"zjh"},{"top10":1,"_id":0})
  • $lt < $lte <= $gt > $gte >= $ne != 比较操作符
  • $in $nin 用来查询一个键的多个可能值
  • $or用来查询多个键的可能值,满足其一即可

db.blog.find({"$or":[{"boys.name":{"$in":["xiaoming,xiaobai"]}},{"boys.age":"xiaohong"}]})

  • $mod db.blog.find({"id_num":{"$mod":[5,1]}})将id_num查询出来除以5,若余数为1则成功匹配
  • 匹配值为null时,为了避免其他没有该键的被匹配到,需要使用$exists:true进行辨别
  • 查询数组特定位置的元素,需要用key.index指定下标 db.blog.find({"fruit.2":"peach"})
  • $size查询特定长度的数组
  • $slice可以指定数据的偏移量,以及希望返回的元素数量
1
2
3
4
lo## 返回匹配到的24~33个元素,总体不够33则返回包含24后面的所有元素(不包含23)
db.blog.find(c,{"comments":{"$slice":[23,10]})
## 获取最后一条信息
db.blog.find(c,{"comments":{"$slice":-1})
  • 返回与查询条件相匹配的任意一个数组元素,可以用$操作符得到一个匹配的元素
1
2
3
4
> db.blog.find({"boys.name":"ymt"},{"top10":1,"_id":0})
{ "top10" : [ "1", "2", "3", "4", "5", "6" ] }
> db.blog.find({"boys.name":"ymt"},{"top10.$":1,"_id":0})
{ "top10" : [ "1" ] }
  • 数组范围查询

$elemMatch当需要对一个内嵌文档的多个键进行操作时

  • 游标查询
1
2
3
4
5
6
7
8
9
10
11
# 将查询出来的数据赋值给一个变量a
var a = db.blog.find()
while(a.hasNext()){
... obj = a.next()
... print(obj._id)
... }
############### 结果显示
ObjectId("610791a94078fb1a0ae704d8")
ObjectId("6108bb4b28821636220bb519")
ObjectId("61090159bcc66a715faa4efb")
ObjectId("61090183bcc66a715faa4efc")
  • 模糊查询
1
2
3
4
5
6
7
8
9
10
11
12
# 某文档包含某字段的模糊查询
db.getCollection('lawsRegulationsMenu_table').find({
"lawsName":{ $regex:/劳动/ }
})
# 查询以某字段为开头的文档
db.getCollection('lawsRegulationsMenu_table').find({
"lawsName":{ $regex:/^劳动/ }
})
# 查询以某字段为结尾的文档
db.getCollection('lawsRegulationsMenu_table').find({
"lawsName":{ $regex:/劳动^/ }
})
  • 分页查询 limit、skip、sort

limit + skip可实现最简单的分页查询,sort用作结果显示的排序,db.blog.find().sort({"username":1,"age":-1})代表了结果按照”username”升序及”age”降序

但是如果每页的数量太大,即每次需要略过的数据偏多,则用limit+skip方式分页会导致性能问题(因为需要找到需要被略过的数据,然后再抛弃这些数据),不建议

  • 游标需要注意的点

结果集较大,利用游标的方式可能会多次返回同一个文档,原因如下:

  1. 开始查找,从集合的开头开始返回,游标往右移动
  2. 更改文档并保存回数据库
  3. 文档体积增大,但是预留空间不足,则文档被移动至末尾处
  4. 游标继续往下,周而复始将因修改后体积过大而无法放回原位置的集合移动至末尾,当最后游标移至末尾,返回那些因体积变大而被移动到集合末尾的文档

索引

指令

db.blog.ensureIndex({"username":1})

db.blog.getIndexes() 查找给定集合上的所有索引信息

db.blog.dropIndex("索引名称") 删除索引

优缺点

添加索引可以帮助我们更快去查找,但是对于每次操作(插入、更新、删除)都将耗费更多时间

索引创建的位置

对文档本身创建索引和对嵌套文档中的某个字段创建索引是完全不同的

  • 对文档本身创建索引时,只有完全匹配才能用到索引
  • 对嵌套文档中某个字段创建索引,那么只要用到了该字段进行搜索,就会用到索引
  • 建议将索引建在基数较高的键上,比如姓名和性别两个属性,将索引建立在姓名上然后匹配性别能够更加快速的查询

强制数据库做全表扫描 $natural

db.blog.find({"username":"user7777"}).hint({"$natural":1})可以强制扫描全表,就算使用了索引也没用,

索引类型

唯一索引

1
2
3
# 如果限制了唯一索引,那么如果再插入相同的索引键内容,则会抛出异常
# 唯一索引键的值,null也同理,不能出现2次
db.blog.ensureIndex({"username":1},{"unique":true})

稀疏索引

和唯一索引不同的是:当有一个不确定是否存在的字段,但你需要保证当他存在时,必须唯一时,用到稀疏索引,解决了上边null的问题

1
2
# 当插入时索引键有值时,必须保证其唯一,当索引键没有值时略过不报错
db.blog.ensureIndex({"username":1},{"unique":true,"sparse":true})

特殊的索引和集合

固定集合

向一个固定集合(集合的空间大小固定)中插入数据时,最老的数据会被新的数据替换可用于日志记录,因为无法确定什么时候数据会被覆盖,所以重要的数据无法存储

  • 创建 db.createCollection("my_coll",{"capped":true,"size":100000,"max":100}),名为my_coll,大小为100000字节,无法改变固定的集合属性,只能删除重建

自然排序

  • 对固定集合可以进行一种特殊的排序–自然排序,该顺序为文档在磁盘上的顺序
1
2
3
# 根据插入的顺序进行排序
db.blog.sort({"$natural" : 1});
db.blog.sort({"$natural" : -1});

循环游标

类似于linux命令中的tail -f实时读取结果(超过10分钟没有新结果就释放,也可人为中止),循环游标只能用在固定集合上

TTL索引(time-to-live index)

生命周期索引,可为文档设置超时时间,过了时间自动删除,可用于缓存,保存会话

1
2
# expireAfterSecs用于创建TTL索引
db.blog.ensureIndex({"a":1},{"expireAfterSecs":60*60*24})

全文本索引

可以非常快的进行文本搜索,如同内置了多种语言的分词机制一样,需要注意的是非常耗内存,匹配到的文档会按照相关性降序排列,只针对字符串进行索引,如同内置分词机制,MongoDB 在 2.6 版本以后是默认开启全文检索的

1
2
3
# 添加name为全文检索索引
db.lawsRegulationsMenu_table.ensureIndex({"name":"text"})
db.lawsRegulationsMenu_table.find({$text:{$search:"tom"}})

默认为搜索"default_language" : "english",中文没有比较好的支持,可以自定义分词库

地理空间索引

可以比较两个地理空间,交集、包含($within)、接近($near 返回距离由近及远的排序)

GridFS存储文件

应用场景:存储一些不常改变但需要连续访问的大文件

使用mongofiles操作GridFS,put、list、get、search、delete操作

通过检验GridFS的块的md5值来确保文件上传正确

聚合

由多个构件创建一个管道,构件包括

  • 筛选 filtering {$match:{"state":"OR"}} 对需要聚合的文档进行筛选
  • 投射 projecting {"$project":{"author":1}} 需要返回哪些字段
  • 分组 grouping {"$group":{"_id":"$author","count":{"$sum":1}}}根据author字段分组,分组内的每个count加1
  • 排序 sorting {"$sort":{"count":-1}}
  • 限制 limiting {"$limit":5}
  • 跳过 skipping

最后将这些构件全部传入aggregate()函数中,$fieldname = fieldname字段所对应的值

  • 控制构件

$cond:[booleanExpr,trueExpr,falseExpr]如果booleanExpr为true,则返回trueExpr否则返回falseExpr

"$ifNull":[expr,replacementExpr] 如果expr为null,返回replacementExpr,否则返回expr

  • 分组操作符 $sum
  • 算术操作符 $sum$average
  • 极值操作符 $max $min $first $last
  • 数组操作符 $addToSet 数组中每个元素最多出现一次 $push 不论值,将它添加在数组中,可出现多次相同元素

$unwind

可以用$unwind将一个数组中每一个数据拆分成一个独立的文档,可以配合$match得到想要的文档

1
db.lawsRegulationsMenu_table.aggregate( {"$project":{"lawsListBeans":"$lawsListBeans"}} ,{"$unwind":"$lawsListBeans"}, {"$match":{"lawsListBeans.lawsListNo":"92f70a43-81db-46ea-ad2c-dae5e2dda3cd"}})
赏个🍗吧
0%