简单了解
MongoDB在Go中是有官方的API接口库的,不过在官方开发库之前,一直是存在个人开发版(mgo),后来交由社区进行维护了,貌似此人也是与MongoDB官方进行合作进行官方库的开发。
官方库大概是2018年出了第一版正式版,现在已经是正在服役阶段了。而不管是社区版还是官方版,且都是在个人版的基础上进行开发,这里都需要感谢niemeyer。
社区版:https://github.com/globalsign/mgo
官方版:https://github.com/mongodb/mongo-go-driver
网上相对较多的资料还是以mgo的为主,比较mongo-go-driver相对较晚,基于同一主干,且mgo也并没有处于废弃状态,所以在使用上依然还是倾向于使用mgo,当然,在官方版更新了好几个版本后,后续会考虑将版本给更换过来。
标识(2019-10)
MongoDB的Go官方库已经是趋于稳定,发布正式版本了,所以作为开发者来说,以后选择官方库应该是最佳选择了,毕竟这个库会一直保持维护的。
但毕竟是一个新的库,网上大部分博客都是关于mgo
这个社区维护版本的库使用方式,这有个库也包含了一些例子可以帮助学习。
mongo-go-examples。
基础操作
连接serve
mgo:
1 2 3 4 5 6 7 8 9 10 11 12 13
| mongo, err := mgo.ParseURL("mongodb://localhost:27017/articles_demo_dev")
s, err := mgo.Dial("mongodb://localhost:27017/articles_demo_dev") if err != nil { fmt.Printf("Can't connect to mongo, go error %v\n", err) panic(err.Error()) }
coll := session.DB(mongo.Database)
coll.C(g.DbModuleBindFile)
|
mongo-go-driver:
1 2 3 4 5 6 7 8 9 10 11
| if client, err = mongo.Connect(context.TODO(), "mongodb://localhost:27017", clientopt.ConnectTimeout(5*time.Second)); err != nil { fmt.Println(err) return }
database = client.Database("my_db")
collection = database.Collection("my_collection")
|
插入数据:
MongoDB的ID是推特很早的时候开源的,tweet的ID。
snowflake: 毫秒/微秒的当前时间 + 机器的ID + 当前毫秒/微秒内的自增ID(每当毫秒变化了, 会重置成0,继续自增)。
mgo:
1 2 3 4 5 6 7 8 9 10 11
| idTest := bson.NewObjectId() err = r.C.Insert(map[string]interface{}{ "test": "ID由开发者指定,否则MongoDB自己生成", "_id": idTest, })
r.C.Insert(&Person{"Heln", "31"}, &Person{"Ana", "32"}, &Person{"A3a", "27"}, &Person{"Awa", "24"})
|
mongo-go-driver:
1 2 3 4 5 6 7 8 9 10 11
| if result, err = collection.InsertOne(context.TODO(), map[string]interface{}{ "test": "ID由开发者指定,否则MongoDB自己生成", "one": "one", }); err != nil { fmt.Println(err) return }
docId = result.InsertedID.(objectid.ObjectID) fmt.Println("自增ID:", docId.Hex())
|
查询
mgo:
1 2
| err = r.C.Find(bson.M{"index_no": "123"}). Select(bson.M{"_id": 0, "test": 1}).One(&tes)
|
**注意:**查询时,select中除了id外,其他要么是1,要么是0,否则将报错,select是选择返回的参数。
mongo-go-driver:
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
| cond = &FindByJobName{JobName: "job10"}
if cursor, err = collection.Find(context.TODO(), cond, findopt.Skip(0), findopt.Limit(2)); err != nil { fmt.Println(err) return }
defer cursor.Close(context.TODO())
for cursor.Next(context.TODO()) { record = &LogRecord{}
if err = cursor.Decode(record); err != nil { fmt.Println(err) return } fmt.Println(*record) }
|
删除
mgo:
1 2
| r.C.Remove(bson.M{"_id": bson.ObjectIdHex(id)}) r.C.RemoveAll(bson.M{"_id": bson.ObjectIdHex(id)})
|
mongo-go-driver:
1 2 3 4 5 6 7 8 9 10 11
|
delCond = &DeleteCond{beforeCond: TimeBeforeCond{Before: time.Now().Unix()}}
if delResult, err = collection.DeleteMany(context.TODO(), delCond); err != nil { fmt.Println(err) return }
fmt.Println("删除的行数:", delResult.DeletedCount)
|
其他操作
计算数组大小
MongoDB获取内嵌数组的长度:
https://stackoverflow.com/questions/21387969/mongodb-count-the-number-of-items-in-an-array
1 2 3 4 5 6
| > db.mycollection.insert({'foo':[1,2,3,4]}) > db.mycollection.insert({'foo':[5,6,7]})
> db.mycollection.aggregate({$project: { count: { $size:"$foo" }}}) { "_id" : ObjectId("5314b5c360477752b449eedf"), "count" : 4 } { "_id" : ObjectId("5314b5c860477752b449eee0"), "count" : 3 }
|
使用Go实现,使用mgo,需要用到聚合操作:
1 2 3 4 5 6 7 8 9 10
| pipe := r.C.Pipe([]bson.M{ {"$match": bson.M{"_id": idTest}}, {"$project": bson.M{"count": bson.M{"$size":"$fileid_bind_module"}}}, }) resp := bson.M{} err = pipe.One(&resp) fmt.Println("error is :", err, resp)
|
另外一种方法:$size数组元素个数。
$addToSet
设置一个字段size
来保存数组的大小,不过这种操作无法与$addToSet
一起进行使用。因为$addToSet
不会在数组中插入重复的数据,而inc操作依然会继续加1
。
1 2 3 4 5 6 7
| err := r.C.Update(map[string]interface{}{ "_id": bson.ObjectIdHex("5bebe0cf7f45aa3270c9e532"), }, bson.M{ "$addToSet": bson.M{ "test": "1234567890", }, })
|
加一个size字段
1 2 3 4
| err = db.C("xxxxxx").Update(bson.M{"_id": tmpFile.Id}, bson.M{ "$push": bson.M{"file_id_list": p.FileIdList[0]}, "$inc": bson.M{"list_size": 1}})
|
MongoDB数组操作
对数组的增删查改,可以学习:MongoDB 数组。
mgo查找单层数组
代码中需要使用到$elemMatch
参数。
[]int{1, 2, 3}
1 2 3
| err = r.C.Find(map[string]interface{}{ "test": bson.M{"$elemMatch": bson.M{"$eq": ids}, }}).One(&bind)
|
mgo查找多层数组
{"_id":"xxxxxx", "testArr": [{"x": "1", "test1": 1}, {"x": "3", "test1": 2}]}
1 2 3 4 5
| var testData interface{} err = r.C.Find(bson.M{ "_id": idTest123, "testArr": bson.M{"$elemMatch": bson.M{"test1": 1}, }}).One(&testData)
|
mgo删除数组元素
删除数组元素,会将该子结构完全删除。
删除单层数组
[]int{1, 2, 3}
1 2 3 4
| err := r.C.Update(bson.M{ "_id": idTest, }, bson.M{"$pull": bson.M{"test": "123"}, })
|
删除两层数组
1 2 3 4
| r.C.Update(bson.M{ "_id": idTest123}, bson.M{"$pull": bson.M{"testArr": bson.M{"test1": 1}}})
|
聚合操作:Aggregation
$match
:类似于find中条件匹配;
$unwind
:将数组拆开,化成一个个独立信息,除了散开的数组字段不同,其他字段均相同;
$skip
与limit
:类似于MongoDB中的skip与limit;
$project
:修改输入文档的结构。可以用来重命名、增加或删除域,指定获取的字段,没有的字段,也可以用于创建计算结果以及嵌套文档。
1 2 3 4 5 6 7 8 9 10
| pipe := r.C.Pipe([]bson.M{ {"$match": bson.M{"_id": idTest123, "product_id": 123}}, {"$unwind": "$testArr"}, {"$skip": 1}, {"$limit": 1}, {"$project": bson.M{"product_id": 1, "one": "$testArr.test1"}}, }) resp := bson.M{} err = pipe.One(&resp)
|
用objectID查询某一时间段内数据
ObjectID是由精确到秒的时间戳再加上机器标识等信息组成的,并且建有索引,因此ObjectID本身就可以用于按时间范围查询数据,而不用专门另建时间戳字段和索引。
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
| func timeToObjId(t int64) string {
return fmt.Sprintf("%x0000000000000000", t) }
func GetUnixToOldTimeDay(i int) int64 { day := time.Now().Day() oldMonth := day - i t := time.Date(time.Now().Year(), time.Now().Month(), oldMonth, time.Now().Hour(), time.Now().Minute(), time.Now().Second(), time.Now().Nanosecond(), time.Local) return t.Unix() }
func objIdOneMonth() (oldMonthId string, nowId string) { timeUinx := GetUnixToOldTimeDay(30)
oldMonthId = timeToObjId(timeUinx) nowId = timeToObjId(time.Now().Unix())
return }
db.C(DbSysMsg).Pipe([]bson.M{ {"$match": bson.M{"_id": bson.M{"$lte": bson.ObjectIdHex(nowId), "$gt": bson.ObjectIdHex(oldMonthId)}}}, {"$limit": 200}, {"$project": bson.M{"count": bson.M{"$size": "user_list_status"}}}, })
|
本文标题:初次使用MongoDB
文章作者:小师
发布时间:2018-11-24
最后更新:2022-05-04
原始链接:chunlife.top/2018/11/24/初次使用MongoDB/
版权声明:本站所有文章均采用知识共享署名4.0国际许可协议进行许可