golang 使用 “gopkg.in/mgo.v2” 查询mongo总结。mongo的增加,更新和删除操作比较简单,查询操作相对灵活复杂一些,下面对golang 查询 mongo 做个总结。完整代码上传到了 https://gitee.com/truthalone/go-mongo.git 。

1.连接 mongo

//mongo.go

package main

import (
	"errors"
	"time"

	"gopkg.in/mgo.v2"
)

// 连接mongodb数据库
var (
	mongodbAddr     string = "" //mongodb数据库地址
	mongodbName     string = "" //mongodb数据名称
	mongodbUser     string = "" //mongodb用户名
	mongodbPassword string = "" //mongodb密码
)

var (
	session *mgo.Session
)

func init() {
	mongodbAddr = "127.0.0.1"
	mongodbName = "demo"
	mongodbUser = "root"
	mongodbPassword = "ming"
}

func GetMongoSession() *mgo.Session {
	if session == nil {
		var err error

		if mongodbUser == "" || mongodbPassword == "" {
			session, err = mgo.Dial(mongodbAddr)
		} else {
			dialInfo := &mgo.DialInfo{
				Addrs:     []string{mongodbAddr},
				Direct:    false,
				Timeout:   time.Second * 30,
				Database:  mongodbName,
				Source:    "admin",
				Username:  mongodbUser,
				Password:  mongodbPassword,
				PoolLimit: 4096, // Session.SetPoolLimit
			}

			session, err = mgo.DialWithInfo(dialInfo)
		}

		if err != nil {
			return nil
		}
	}

	return session.Clone()
}

func WithMongoCollection(collectionName string, s func(*mgo.Collection) error) error {
	session := GetMongoSession()
	if session == nil {
		return errors.New("获取mongodb连接失败")
	}
	defer session.Close()

	c := session.DB(mongodbName).C(collectionName)
	return s(c)
}

2.插入数据

插入的数据包含子文档和数组数据,平时比较复杂的查询也是子文档查询和数组查询

//book.go

//图书
type Book struct {
	Id      bson.ObjectId `bson:"_id"`    //主键
	Name    string        `bson:"name"`   //图书名称
	Price   float32       `bson:"price"`  //价格
	Authors []Author      `bson:"author"` //作者
	Tags    []string      `bson:"tags"`   //标签
	Press   string        `bson:"press"`  //出版社
}

//作者
type Author struct {
	Name string `bson:"name"` //姓名
	Sex  string `bson:"sex"`  //性别
}

const (
	BookCollection = "book"
)

func NewBook(name string, price float32, authors []Author, tags []string, press string) *Book {
	b := &Book{
		Name:    name,
		Price:   price,
		Authors: authors,
		Tags:    tags,
		Press:   press,
	}

	b.Id = bson.NewObjectId()

	return b
}

func insert() {
	//声明为interface数组,才能批量插入
	books := make([]interface{}, 0, 10)

	book1 := NewBook("高等数学上", 37.70, []Author{{"同济大学数学系", ""}}, []string{"数学", "大学数学", "高等数学"}, "高等教育出版社")
	books = append(books, book1)

	book2 := NewBook("TCP/IP详解卷1:协议", 45.00,
		[]Author{{"W.Richard Stevens", "男"}, {"范建华", "男"}, {"胥光辉", "男"}, {"张涛", "男"}, {"谢希仁", "男"}},
		[]string{"计算机网络", "网络协议", "编程"}, "机械工业出版社")
	books = append(books, book2)

	book3 := NewBook("Python程序设计开发宝典", 69.00, []Author{{"董付国", "男"}}, []string{"程序设计", "编程", "python"}, "清华大学出版社")
	books = append(books, book3)

	book4 := NewBook("汇编语言", 36.00, []Author{{"王爽", ""}}, []string{"程序设计", "编程", "汇编"}, "清华大学出版社")
	books = append(books, book4)

	book5 := NewBook("SparkSQL入门与实践指南", 49.00, []Author{{"纪涵", "女"}, {"靖晓文", "女"}, {"赵政达", "男"}},
		[]string{"程序设计", "编程", "spark", "spark sql"}, "清华大学出版社")
	books = append(books, book5)

	expr1 := func(c *mgo.Collection) error {
		return c.Insert(books...)
	}

	err := WithMongoCollection(BookCollection, expr1)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	fmt.Println("插入成功")
}

3.定义查询输出

func searchAll(query bson.M) {
	var books []Book
	expr := func(c *mgo.Collection) error {
		return c.Find(query).All(&books)
	}

	err := WithMongoCollection(BookCollection, expr)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	if len(books) == 0 {
		fmt.Println("未找到记录...")
		return
	}

	for _, book := range books {
		fmt.Println(book)
	}
}

4.简单条件查询

//单个条件 =
func equal() {
	query := bson.M{"name": "Python程序设计开发宝典"}
	searchAll(query)
}

//单个条件 >
func gt() {
	query := bson.M{"price": bson.M{"$gt": 40.0}}
	searchAll(query)
}

//单个条件 <
func lt() {
	query := bson.M{"price": bson.M{"$lt": 40.0}}
	searchAll(query)
}

//单个条件 >=
func gte() {
	query := bson.M{"price": bson.M{"$gte": 45}}
	searchAll(query)
}

//单个条件 <=
func lte() {
	query := bson.M{"price": bson.M{"$lte": 36}}
	searchAll(query)
}

//单个条件 !=
func ne() {
	query := bson.M{"press": bson.M{"$ne": "清华大学出版社"}}
	searchAll(query)
}

5. 多合条件查询

// and
//select * from table where price<=50 and press='清华大学出版社'
func and() {
	query := bson.M{"price": bson.M{"$lte": 50}, "press": "清华大学出版社"}
	searchAll(query)
}

// or
//select * from table where press='高等教育出版社' or press='清华大学出版社'
func or() {
	query := bson.M{"$or": []bson.M{bson.M{"press": "高等教育出版社"}, bson.M{"name": "Python程序设计开发宝典"}}}
	searchAll(query)
}

// not
// not条件只能用在正则表达式中
func not() {
	query := bson.M{"press": bson.M{"$not": bson.RegEx{Pattern: "^清华", Options: "i"}}}
	searchAll(query)
}


// 单个key的or查询可以使用 in 或 nin
func in() {
	query := bson.M{"press": bson.M{"$in": []string{"清华大学出版社", "机械工业出版社"}}}
	searchAll(query)
}

func nin() {
	query := bson.M{"press": bson.M{"$nin": []string{"清华大学出版社", "机械工业出版社"}}}
	searchAll(query)
}

6. 正则查询,字符串模糊查询

//正则查询
//$regex操作符的使用
//
//$regex操作符中的option选项可以改变正则匹配的默认行为,它包括i, m, x以及s四个选项,其含义如下
//
//i 忽略大小写,{<field>{$regex/pattern/i}},设置i选项后,模式中的字母会进行大小写不敏感匹配。
//m 多行匹配模式,{<field>{$regex/pattern/,$options:'m'},m选项会更改^和$元字符的默认行为,分别使用与行的开头和结尾匹配,而不是与输入字符串的开头和结尾匹配。
//x 忽略非转义的空白字符,{<field>:{$regex:/pattern/,$options:'m'},设置x选项后,正则表达式中的非转义的空白字符将被忽略,同时井号(#)被解释为注释的开头注,只能显式位于option选项中。
//s 单行匹配模式{<field>:{$regex:/pattern/,$options:'s'},设置s选项后,会改变模式中的点号(.)元字符的默认行为,它会匹配所有字符,包括换行符(\n),只能显式位于option选项中。
//
//使用$regex操作符时,需要注意下面几个问题:
//
//i,m,x,s可以组合使用,例如:{name:{$regex:/j*k/,$options:"si"}}
//在设置索引的字段上进行正则匹配可以提高查询速度,而且当正则表达式使用的是前缀表达式时,查询速度会进一步提高,例如:{name:{$regex: /^joe/}

//字符串模糊查询  开头包含
func beginWith() {
	query := bson.M{"name": bson.M{"$regex": bson.RegEx{Pattern: "^高等", Options: "i"}}}

	searchAll(query)
}

//模糊查询 包含
func contains() {
	//query := bson.M{"name": bson.M{"$regex": "开发", "$options": "$i"}}
	query := bson.M{"name": bson.M{"$regex": bson.RegEx{Pattern: "开发", Options: "i"}}}
	searchAll(query)
}

//模糊查询 结尾包含
func endWith() {
	query := bson.M{"name": bson.M{"$regex": bson.RegEx{Pattern: "指南$", Options: "i"}}}
	searchAll(query)
}

7.数组查询

//数组查询,数组中的元素可能是单个值数据,也可能是子文档
//针对单个值数据
//满足数组中单个值
func arrayMatchSingle() {
	query := bson.M{"tags": "编程"}
	searchAll(query)
}

//同时满足所有条件,不要求顺序
func arrayMatchAll() {
	query := bson.M{"tags": bson.M{"$all": []string{"程序设计", "编程", "python"}}}
	searchAll(query)
}

//查询特定长度
func arrayMatchSize() {
	query := bson.M{"tags": bson.M{"$size": 4}}
	searchAll(query)
}

//满足特定索引下条件
//数组索引从0开始,我们匹配第二项就用tags.1作为键
func arrayMatchIndex() {
	query := bson.M{"tags.1": "编程"}
	searchAll(query)
}

//精确查找,数量,顺序都要满足
func arrayMatch() {
	query := bson.M{"tags": []string{"数学", "大学数学", "高等数学"}}
	searchAll(query)
}

//针对与数组中的子文档
//满足单个价值
func subDocMatchSingle() {
	query := bson.M{"author.name": "纪涵"}
	searchAll(query)
}

//elementMath
func subDocMatchElement() {
	query := bson.M{"author": bson.M{"$elemMatch": bson.M{"name": "谢希仁", "sex": "男"}}}
	searchAll(query)
}

8.聚合管道查询

定义[]bson.M查询条件数组,依次执行

//记数
func count() {
	var count int
	expr := func(c *mgo.Collection) error {
		var err error
		count, err = c.Find(bson.M{}).Count()
		return err
	}

	err := WithMongoCollection(BookCollection, expr)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	fmt.Println(count)
}


//去重
func distinct() {
	var result []interface{}
	expr := func(c *mgo.Collection) error {
		return c.Find(bson.M{}).Distinct("press", &result)
	}

	err := WithMongoCollection(BookCollection, expr)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	fmt.Println(result)

}


//求和
//golang mongo 管道查询中,可以先使用"$match"过滤出复合条件的数据,
//然后使用"$project"投射出想要的结果字段,然后使用 "$group" 进行分组聚合。
//"$group" 根据 "_id"来分组,可以通过多个字段来定义 "_id"来进行分组。

func sum() {
	query := []bson.M{
		//bson.M{"$match": bson.M{"press": "清华大学出版社"}},
		bson.M{"$project": bson.M{"_id": 0, "price": 1, "press": 1}},
		bson.M{"$group": bson.M{"_id": "$press", "totalPrice": bson.M{"$sum": "$price"}}},
	}

	var result []bson.M
	expr := func(c *mgo.Collection) error {
		return c.Pipe(query).All(&result)
	}

	err := WithMongoCollection(BookCollection, expr)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	fmt.Println(result)
}

//最大值和最小值
func maxAndMin() {
	query := []bson.M{
		bson.M{"$group": bson.M{"_id": nil,"maxPrice": bson.M{"$max": "$price"},"minPrice":bson.M{"$min":"$price"}}},
	}

	var result []bson.M
	expr := func(c *mgo.Collection) error {
		return c.Pipe(query).All(&result)
	}

	err := WithMongoCollection(BookCollection, expr)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	fmt.Println(result)
}

//平均值
func avg(){
	query := []bson.M{
		bson.M{"$group": bson.M{"_id": nil,"avgPrice": bson.M{"$avg": "$price"}}},
	}

	var result []bson.M
	expr := func(c *mgo.Collection) error {
		return c.Pipe(query).All(&result)
	}

	err := WithMongoCollection(BookCollection, expr)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	fmt.Println(result)
}