A类型表示有序的BSON数组。
bson.A{"bar", "world", 3.14159, bson.D{{"qux", 12345}}}
D类型表示包含有序元素的BSON文档。这种类型应该在顺序重要的情况下使用。如果元素的顺序无关紧要,则应使用M代替。
bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
M类型表示无序的映射。
bson.M{"foo": "bar", "hello": "world", "pi": 3.14159}
E类型表示D里面的一个BSON元素。
Raw类型代表未处理的原始BSON文档和元素,Raw系列类型用于验证和检索字节切片中的元素。当要查找BSON字节而不将其解编为另一种类型时,此类型最有用。
Mongo-Driver驱动包官方文档
BSON包官方文档
mongo包官方文档
options包官方文档
package mainimport (
"fmt"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type DB struct {
Session*mgo.Session
Collection *mgo.Collection
}
type Digapp struct {
App_id string
Fetch_url string
From string //
Fetch_statebool
Fetch_priority int32 //
Create_timeint64 //
Invalidbool // + app is access now ?
}
func main() {
db := new(DB)
if err := db.DBInit()err != nil {
fmt.Println("初始化数据库失败!错误为:" + err.Error())
return
}
defer db.Close()
var digapp Digapp
//selector := bson.M{"fetch_priority": 5, "invalid": false}
//selector := bson.M{"fetch_priority": 5, "from": bson.M{"$ne": "dig"}, "invalid": false}
selector := bson.M{"from": "KeywordsSearch"}
db.SetCollection("digapp")
iter := db.GetIter(nil, selector)
for iter.Next(&digapp) {
fmt.Println(digapp)
}
}
func (db *DB) DBInit() error {
var err error
db.Session, err = mgo.DialWithInfo(&mgo.DialInfo{Addrs: []string{MongoDBUrl}, Username: Username, Password: Password})
if err == nil {
db.Session.SetSafe(&mgo.Safe{WMode: WMode})
}
return err
}
func (db *DB) Close() {
db.Session.Close()
}
func (db *DB) SetCollection(collection string) {
db.Collection = db.Session.DB(MongoDBName).C(collection)
}
func (db *DB) GetIter(condition interface{}, selector bson.M, sortor ...string) *mgo.Iter {
return db.Collection.Find(condition).Select(selector).Iter()
}
当使用selector := bson.M{"fetch_priority": 5, "invalid": false}时,输出的是正确抓取到的值;
当使用selector := bson.M{"fetch_priority": 5, "from": bson.M{"$ne": "dig"}, "invalid": false}时,什么都抓不到(没有任何输出信息);
当使用selector := bson.M{"from": "KeywordsSearch"}时,输出的是{ KeywordsSearch false 0 0 false}。
真是奇哉怪也.搞了一早上搞得头大也没弄清楚到底是什么状况。
本项目用于移动端的数据统计,项目地址: https://github.com/lt90s/goanalytics 。开源的数据统计countly做的很好,但是基础免费版的功能实在不够看,因此我就决定用go语言来写了这个项目,一来可以在实践中学习go语言,二来也可以开发功能完整的开源平台。该项目正在开发中,欢迎有兴趣的gopher一起参与。
数据存储方面使用的是mongodb。由于数据统计业务几乎不涉及到事务以及严格的一致性场景,而且mongodb的自动分片功能可以支撑较大的数据量。使用大数据的存储组件的话就太过于重了。因此选用mongodb。
业务逻辑整体基于事件的发布订阅。当收到客户端请求, frontend 会对请求数据进行处理,然后发布响应的事件。 backend 收到事件后进行统计处理。
后台展示基于Vue-Admin-Template开发,本人前端能力基本就是依葫芦画瓢,希望有前端大神来开发后台页面,项目地址: https://github.com/lt90s/goanalytics-web
目前客户端API仅有2个。一个是上报 openApp 打开APP时间,一个是上报 usageTime 一次启动使用时长事件。SDK方面也需要移动端的大神开发,感兴趣的大佬可以一起开发。
下面放一点后台页面的效果图:
GoAnalytics是基于go实现的一个数据统计平台,用于统计移动端的数据指标,比如启动次数、用户增长、活跃用户、留存等指标分析。前端数据展示项目是 goanalytics-web 。目前正在积极开发中,欢迎提交新的需求和pull request。
Go版本需要支持module,本地开发测试
cmd/goanalytics_kafka 和 goanalytics_rmq 是分别基于 kafka 和 rocketmq 的发布订阅功能做的数据发布
和订阅处理,横向扩展能力比 local 高。另外由于 rocketmq 还没有原生基于 go 的客户端(原生客户端正在开发中
2.0.0 road map ),可能会存在问题。
项目结构
├── README.md
├── api
│ ├── authentication 用户认证、管理API
│ ├── middlewares GIN 中间件
│ └── router API route
├── cmd
│ ├── account 生成admin账号命令
│ ├── analytic_local 不依赖消息系统的goanalytics
│ ├── goanalytics_kafka 基于kafak的goanalytics
│ ├── goanalytics_rmq 基于rocketmq的goanalytics
│ └── test_data 生成测试数据命令
├── common
│ └── data.go
├── conf配置
│ └── conf.go
├── event
│ ├── codec 数据编解码
│ └── pubsub 消息发布订阅
├── go.mod
├── go.sum
├── metric 所有的统计指标在这里实现
│ ├── init.go
│ └── user用户相关指标的实现
├── schedule
│ └── schedule.go 定时任务调度
├── storage 存储模块
│ ├── counter.go 计数器接口
│ ├── data.go
│ └── mongodb 基于mongodb实现的存储及计数器
└── utils
├── date.go
├── date_test.go
├── errors.go
└── key.go