简介
mongodb是著名的非关系型数据库,常用来存储大量关联性不大的数据。golang操作mongo数据库可选的库很多,目前主流的使用为”go.mongodb.org/mongo-driver/mongo”,本文通过代码demo的方式介绍go如何操作mongo,实现增删改查,以及多条更新,分组查询,分页查询等复杂查询,代码demo选自个人博客系统的源码。源码地址https://github.com/secondtonone1/bstgo-blog
初始化连接和断开连接
初始化连接,包含必要的mongo-driver库即可
1 | import( |
当服务器关闭时要回收mongo的资源,这里简单关闭即可
1 | func MongoRelease() { |
文章表结构
在go文件中定义ArticleInfo类
1 | //文章信息 |
字段的tag中一定要写bson标识,用来通知mongo以该bson指定的名字存储该字段,json可以不写,我这里写json是为了数据传输
接下来看一下mongo数据库表中的文章信息结构表
1 | { |
数据库表中的数据字段和go程序定义的结构体bson命名的字段是相符合。
查找一条数据
我们根据文章id获取文章信息,代码如下
1 | //通过文章获取文章概要信息 |
查找多条数据
查询未分组的文章列表,这里用到了Find函数,返回的是一个cursor,通过不断的cursor.Next获取每条记录。而且Find设置了查询选项,用了or或查询,这个或查询的条件就是cat为default或者subcat为default,同时对查询结果设置了排序
1 | //获取未分类的文章 |
插入一条数据
这里直接调用insertone传入我们定义的结构体,mongo-driver会自动根据bson命名写入mongo
1 | func SaveArtInfo(article *model.ArticleInfo) error { |
更新一条数据
根据文章id更新浏览量
1 | //更新文章浏览量 |
更新时设置filter为更新的条件,value为更新的字段值,这里实现的是浏览量自增运算,如果要实现覆盖式更新也很简单
1 | //更新文章 |
更新多条
批量更新满足条件的多条记录,比如更新一个序列的文章列表,将其分类和子分类都更新为指定字段
1 | //批量更新默认文章的分类 |
上述代码将arts数组中的文章列表,统一更新了分类为cat,子分类为subcat
如果需要将多条记录,更新成多个不同的值怎么处理呢?这里要用到bulkwrite
1 | //批量更新文章列表序列 |
上述代码将文章列表的多个文章的index更新为不同的值,index代表文章的排序索引,将不同文章的index值更新为不同的index,达到的效果就是id为1的文章index索引更新为index1,id为2的文章index更新为index2
分页查询
可以对查询选项设置排序,并且设置每次获取多少条记录从而达到分页查询的效果。比如将skipTmp设置为5,10,15,将limitTmp设置为5就是每页获取五条记录,将sort设置为按照lastedit排序,就达到了根据最后编辑日期排序,并分页查询,获取每页五条数据的功能。
1 | //获取文章列表 |
获取文档总记录数量
有时我们需要获取一个文档的所有记录数,比如分页查询后也要返回总的页数,这其实就是需要查询出总的条数计算返回总页数即可。
1 | //获取文章总数 |
CountDocuments返回的是文档总的记录条数
模糊查询
我们可以根据年月日以及分类查询,返回文章列表,当然还可以通过输入keywords关键字进行模糊查询。这里做一个较为复杂的查询,查询条件为某年某月某日创建的文章,分类为cat,并根据keywords模糊查询,如果文章内容或标题中有符合keywords的,返回该文章列表。
1 | //搜索文章 |
分组查询
我们常遇到这种情况,查询每个班级成绩最好的学生,或者查询每个类别销量最好的产品品牌等,这里我也用到了分组查询,根据不同分类返回每个分类下最大index值,这样做主要是统计每个分类下文章最大索引。
1 | //获取子分类下最大index |
通过match匹配subcat,然后根据匹配结果进行分组,分组的区分的条件为subcat,分组条件的字段要用_id(只能用这个名字)表示,然后用maxIndex(可以自己命名)表示获取分组的最大索引。
当然我们还可以做一些分组运算的其他操作
1 | //分组查询 |
先用birthday做查询,匹配三月份出生的人,然后根据月份进行分组,totalCount用来计算分组下人的总数,nameG表示最小名字等。
文档内查询
有时候mongo的文档中的记录形式为一条记录,该记录有多个字段,某个字段为一个数组列表,查询记录中数组列表某个值满足条件,返回该记录。我有这样一个文档,表示文章的目录菜单
1 | { |
当想查询文档内catid为1wZezd7c961MNGZ0s0U8aUef4hq的片段,并且更新其subcatmenus字段为新的数组
db.menu.find({“catmenus.catid”:”1wZezd7c961MNGZ0s0U8aUef4hq”})是可以查询到该记录的,
但是这种查询只限于单个条件,
如果有多个条件如下db.menu.find({“catmenus.catid”:”1wZezd7c961MNGZ0s0U8aUef4hq”,”catmenus.name”:”Go”})
如果有多条记录分别满足条件,查询的就有可能是多条,而不是交集,mongo返回满足以上条件任意一条即可。
为了要实现交集选择器,则需要用elemMatch
db.menu.find({“catmenus”: {“$elemMatch”:{“catid”:”1wZezd7c961MNGZ0s0U8aUef4hq”, “name”:”Go”}}})
转化为go代码实现查询
1 | func UpdateSortMenu(submenu *model.SortMenuReq) error { |
目前收录了几种常见的go操作mongo的方法,都是基于mongo原生支持的操作实现的。