Golang操作MongoDB数据库

本文基于 Golang 的爬虫框架 Go-Colly 进行数据抓取,然后存储到 MongoDB 数据库。根据搜索结果,相对来说最成熟的 MongoDB 驱动,应该是 mgo,但是目前 mgo 的作者已经停止维护。另外 MongoDB 官方也已经有对应 Golang 的驱动 mongo-go-driver,但是 Google 上相关的资料并不多。

1. Mgo 驱动

~~ 地址: https://godoc.org/labix.org/v2/mgo ~~

地址: https://github.com/globalsign/mgo

文档: https://godoc.org/github.com/globalsign/mgo

说明:上面第一个地址,是 mgo 的原地址,目前作者已经停止维护。第二个地址是基于原作者的社区维护版本,也是作者推荐的方案之一。

请参考相关项目中的使用:

https://github.com/phpha/gocolly-beike

本文以下内容请忽略,不建议使用。


2. 官方驱动

地址: https://github.com/mongodb/mongo-go-driver

文档:https://godoc.org/github.com/mongodb/mongo-go-driver/mongo

说明:遇到些问题,相关资料不是很多,尤其是缺少 Demo 可以参考。

3. 官方驱动简单测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# service/client.go
package mongodb

import (
	"context"
	"fmt"
	"github.com/mongodb/mongo-go-driver/mongo"
	"github.com/mongodb/mongo-go-driver/mongo/findopt"
	"log"
)

const (
	MONGODB  string = "mongodb://localhost:27017"
	DATABASE string = "test"
)

func GetClient() *mongo.Client {
	client, err := mongo.NewClient(MONGODB)
	if err != nil {
		log.Fatal(err)
	}
	err = client.Connect(context.TODO())
	if err != nil {
		log.Fatal(err)
	}
	return client
}

// 查询
func Find(client *mongo.Client, collection_name string, filter interface{}, opts ...*options.FindOptions) mongo.Cursor {
	collection := client.Database(dbName).Collection(collection_name)
	cur, err := collection.Find(context.Background(), filter, opts...)
	if err != nil {
		log.Fatal(err)
	}
	defer cur.Close(context.Background())
	return cur
}

// 查询单条
func FindOne(client *mongo.Client, collection_name string, filter interface{}) *bson.Document {
	collection := client.Database(dbName).Collection(collection_name)
	result := bson.NewDocument()
	err := collection.FindOne(context.Background(), filter).Decode(result)
	if err != nil {
		log.Fatal(err)
	}
	return result
}

// 计数
func Count(client *mongo.Client, collection_name string, filter interface{}) int64 {
	collection := client.Database(dbName).Collection(collection_name)
	res, err := collection.Count(context.Background(), filter)
	if err != nil {
		log.Fatal(err)
	}
	return res
}

// 插入
func Insert(client *mongo.Client, collection_name string, document interface{}) interface{} {
	collection := client.Database(dbName).Collection(collection_name)
	res, err := collection.InsertOne(context.Background(), document)
	if err != nil {
		// fmt.Print(err)
		return ""
	}
	return res.InsertedID
}

// 更新
func Update(client *mongo.Client, collection_name string, filter interface{}, document interface{}, opts ...*options.FindOneAndUpdateOptions) bool {
	collection := client.Database(dbName).Collection(collection_name)
	res := collection.FindOneAndUpdate(context.Background(), filter, document, opts...)
	if res.Decode(res) != nil {
		return false
	}
	return true
}

// 删除
func Delete(client *mongo.Client, collection_name string, filter interface{}) int64 {
	collection := client.Database(dbName).Collection(collection_name)
	res, err := collection.DeleteOne(context.Background(), filter)
	if err != nil {
		log.Fatal(err)
	}
	return res.DeletedCount
}

目前遇到的问题就是,在查询时,不加任何条件,但是每次最多只能返回 101 条数据。

如果配合上 limit(N) ,当 N 大于 101 时,也依然无效。暂时未找到原因。

临时方案就是多次分页查询,比如我每次查询 100 条,多次查询。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 数据库
client := mongodb.GetClient()
// 查询商圈
count := mongodb.Count(client, "bizcircle", map[string]interface{}{})
for i := 1; i <= int(math.Ceil(float64(count)/float64(100))); i++ {
	cur := mongodb.Find(client, "bizcircle", map[string]interface{}{}, []findopt.Find{findopt.Skip(int64((i - 1) * 100)), findopt.Limit(100)})
	// 循环遍历
	for cur.Next(context.Background()) {
		elem := bson.NewDocument()
		err := cur.Decode(elem)
		if err != nil {
			log.Fatal(err)
		}
		// 当前商圈
		bizcircleId := elem.LookupElement("bizcircle_id").Value().StringValue()
		// 后续处理
	}
}