之前习惯了 python/js 这种语法,感觉很自然很方便。
今天看了下 MongoDB 官方的 Go 接口,哎呀,那交互方式,真的是痛苦。
例如查询用户为 1 的用户:{userid: 1},在 Go 里面你还得包裹为 bson.D{{"userid", 1}}
返回的结果是一个索引,要 Decode 下,Docode 还需要传递一个结构体过去。
还得传递一个 context (还没看为啥要这么做,其他语言不用)
感觉一点也不方便,代码很多不美观不优雅,习惯了 js/python 这种比较简单直观的语法,难以接受呀。
感觉 Google 最近出的东西,语法都那么特立独行的,还有一个是死亡嵌套 Flutter ,嵌套到怀疑人生。
官方教程: https://www.mongodb.com/blog/post/mongodb-go-driver-tutorial
filter := bson.D{{"name", "Ash"}}
update := bson.D{
{"$inc", bson.D{
{"age", 1},
}},
}
updateResult, err := collection.UpdateOne(context.TODO(), filter, update)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Matched %v documents and updated %v documents.\n", updateResult.MatchedCount, updateResult.ModifiedCount)
1
EPr2hh6LADQWqRVH 2021-10-24 11:54:16 +08:00
主要是因为 Go 里你可以自己安排内存,而这个库不想替你管理内存。
其实别的语言也一样,当一个组件不想建堆内存的时候,代码都一样拧巴。 |
2
EPr2hh6LADQWqRVH 2021-10-24 11:57:44 +08:00
哦我收回我的话,这不是主要原因。
主要原因就是 Go 描述动态对象太拧巴了 |
3
Rache1 2021-10-24 12:00:59 +08:00
封装一下,应该还行
|
4
codehz 2021-10-24 12:02:39 +08:00 via Android
context 这个可以洗一下,它可以用于在请求撤销的时候撤回发出去的其他请求,避免了资源的浪费,在 go 的主要应用场景--中间件方面意义重大
JS 里也有类似的东西,叫 AbortSignal (虽然 context 功能上更多一点,这里只考虑它的这个功能( |
5
cheng6563 2021-10-24 12:43:29 +08:00
静态语音就是这样的,对接第三方的时候都是先定义模型,再用这个模型的实例去做交互。
通常用泛型会简化一点这种操作,但是 go 。。。 |
6
balabalaguguji OP @Rache1 #3 好像不好封装,Go 里面没有支持任意类型的 Map
|
7
balabalaguguji OP @codehz #4 这个特性感觉我都用不到,但是每次都得写,感觉就有点强制多余了
|
8
balabalaguguji OP @cheng6563 #5 嗯,静态语言应该都是要先定义模型,太不灵活了。
|
9
XTTX 2021-10-24 13:33:26 +08:00
官方 doc 就劝退了, 那你还是千万别用 go+mongoDB 了
|
10
XTTX 2021-10-24 13:34:26 +08:00 2
//FindReadingListArticleAction finds if articleAction exists by checking articleId and ownerID
func (aam *articleActionDB) FindUserArticleActionArticle(ownerID primitive.ObjectID) (*[]Article, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() client, err := mongo.Connect(ctx, options.Client().ApplyURI(aam.connectionString)) if err != nil { return nil, err } defer client.Disconnect(ctx) collection := client.Database(aam.dataBaseName).Collection(aam.collectionName) matchStage := bson.D{{"$match", bson.M{"ownerID": ownerID}}} projectStage := bson.D{{"$project", bson.M{"articleID": 1}}} type articleID struct { ArticleID primitive.ObjectID `bson:"articleID"` } var articleIDs []articleID cursor, err := collection.Aggregate(ctx, mongo.Pipeline{matchStage, projectStage}) if err != nil { fmt.Println(err) return nil, err } if err = cursor.All(ctx, &articleIDs); err != nil { return nil, err } articleClient, err := mongo.Connect(ctx, options.Client().ApplyURI(aam.connectionString)) if err != nil { return nil, err } defer articleClient.Disconnect(ctx) articleCollection := client.Database("crawler").Collection("article") var articles []Article var article Article for i := 0; i < len(articleIDs); i++ { err := articleCollection.FindOne(ctx, bson.M{"_id": articleIDs[i].ArticleID}).Decode(&article) if err != nil { fmt.Println(err) } articles = append(articles, article) } return &articles, nil } 我 6 个月前写的,我现在完全看不懂当初写了什么寂寞 |
11
XTTX 2021-10-24 13:39:57 +08:00
````
//FindFinishedListArticleAction finds if articleAction exists by checking articleId and ownerID func (aam *articleActionDB) FindFinishedListArticleAction(ownerID primitive.ObjectID) (*[]Article, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() client, err := mongo.Connect(ctx, options.Client().ApplyURI(aam.connectionString)) if err != nil { return nil, err } defer client.Disconnect(ctx) collection := client.Database(aam.dataBaseName).Collection(aam.collectionName) matchStage := bson.D{{"$match", bson.M{"ownerID": ownerID}}} matchStage1 := bson.D{{"$match", bson.M{"finisheddate": bson.M{"$exists": true}}}} projectStage := bson.D{{"$project", bson.M{"articleID": 1}}} type articleID struct { ArticleID primitive.ObjectID `bson:"articleID"` } var articleIDs []articleID cursor, err := collection.Aggregate(ctx, mongo.Pipeline{matchStage, matchStage1, projectStage}) if err != nil { fmt.Println(err) return nil, err } if err = cursor.All(ctx, &articleIDs); err != nil { return nil, err } articleClient, err := mongo.Connect(ctx, options.Client().ApplyURI(aam.connectionString)) if err != nil { return nil, err } defer articleClient.Disconnect(ctx) articleCollection := client.Database("crawler").Collection("article") var articles []Article var article Article for i := 0; i < len(articleIDs); i++ { err := articleCollection.FindOne(ctx, bson.M{"_id": articleIDs[i].ArticleID}).Decode(&article) if err != nil { fmt.Println(err) } articles = append(articles, article) } return &articles, nil } ```` 这种东西写的难受, 看得更难受。 |
12
pengtdyd 2021-10-24 13:41:20 +08:00 7
说这话的人显然没有写过 rust
|
13
wxlwsy 2021-10-24 14:07:33 +08:00
你应该没写过原生 JDBC 代码,否则也不会这么说了。
|
14
darksword21 2021-10-24 14:15:13 +08:00 via iPhone
那是相当难受了,特别层级很多的话每层都要检查 err
|
15
Kisesy 2021-10-24 14:20:09 +08:00
mongo 官方库就是不好用,有点底层,当然我没用过不好评价
他这设计有些不对,各种操作必须要传 ctx 这也太那啥了,本来 Go 的操作就繁琐 完全可以写成 collection.WithCtx(context.TODO()).UpdateOne(filter, update),想用 ctx 的时候才调用 要是 Go 能支持默认参数就好了,能省很多事 |
16
XTTX 2021-10-24 14:47:46 +08:00
@Kisesy 我猜当初设计的时候,mongoDB 就是要做 data warehouse,所以必须读 ctx withTimeout 。mongoDB 的市场营销是所有 tech 里做得最好的, 让所有人都觉得其他人都在用 mongoDB 。 官网的文档那叫一个省事,复杂一点的查询方式根本不介绍。 当初我找查询的语法,真的找到吐血。
|
17
balabalaguguji OP @XTTX #10 写个复杂点的 aggregate 感觉会代码量巨大,巨难理解
|
18
balabalaguguji OP @pengtdyd #12 没写过,还有比这更蛋疼的
|
19
balabalaguguji OP @wxlwsy #13 写过,真没这个难受
|
20
Weny 2021-10-24 15:09:54 +08:00
简单的 filter 可以自己封装一下,几百行代码的事情。
```GO import ( "context" "fmt" "strings" ) func initQuery() *Query { q := Query{ operation: "", options: nil, conditions: make(M), field: "", } return &q } func NewQuery(fn ...func(query *Query)) *Query { q := Query{ operation: "", options: &Options{ skip: 0, projection: make(M), }, conditions: make(M), field: "", } if len(fn) > 0 { for _, f := range fn { f(&q) } } return &q } func SetConn(c Connection) func(query *Query) { return func(query *Query) { query.connection = c } } func NewQueryWitConn(c Connection) *Query { return NewQuery(SetConn(c)) } type Query struct { connection Connection operation string options *Options conditions M field string model interface{} } func (q *Query) GetConditions() M { return q.conditions } func (q *Query) GetSelect() M { return q.options.projection } func mappingStringToFieldSets(value Input, projection bool) Input { out := -1 if projection { out = 0 } obj := make(M) switch value.(type) { case string: strArray := strings.Fields(strings.TrimSpace(value.(string))) for _, v := range strArray { if v[0] == '-' { v = v[1:] obj[v] = out } else { obj[v] = 1 } } case M: obj = value.(M) } return obj } func (q *Query) Sort(value interface{}) *Query { q.options.sort = mappingStringToFieldSets(value, false).(M) return q } func (q *Query) Select(value interface{}) *Query { q.options.projection = mappingStringToFieldSets(value, true).(M) return q } func (q *Query) Skip(value int32) *Query { q.options.skip = value return q } func (q *Query) Where(args ...interface{}) *Query { //q.field = field switch len(args) { // first args is string case 1: if field, ok := args[0].(string); ok { q.Set(field) } // Where("version",1) where version is equals q case 2: if field, ok := args[0].(string); ok { q.Set(field).Eq(args[1]) } // Where("version",">=",1) gte 1 case 3: if field, ok := args[0].(string); ok { q.Set(field) } if operators, ok := args[1].(string); ok { q.bindCondition( chain( getFlagWrapperFromString(operators), inputBuilder, )(args[2]), ) } } return q } func (q *Query) Set(field string) *Query { q.field = field return q } func (q *Query) Eq(input interface{}) *Query { q. ensureField("Eq"). bindCondition( chain( inputLogger, inputBuilder, )(input), ). resetField() return q } func (q *Query) Equals(input interface{}) *Query { q. ensureField("Equals"). bindCondition( chain(inputBuilder)(input), ). resetField() return q } func (q *Query) AutoBindConditions(flag string, condition interface{}) *Query { if q.hasField() { q.bindCondition( chain( inputBuilder, )(condition), ).resetField() } else { q.bindCondition( chain( inputWrapper(flag), inputBuilder, )(condition), ).resetField() } return q } /* e.g. query.Or([]M{{"name": "weny"}, {"age": "20"}}) */ func (q *Query) Or(value interface{}) *Query { flag := "$or" return q.AutoBindConditions(flag, value) } /* e.g. query.Nor([]M{{"name": "weny"}, {"age": "20"}}) */ func (q *Query) Nor(value interface{}) *Query { flag := "$nor" return q.AutoBindConditions(flag, value) } func (q *Query) And(value interface{}) *Query { flag := "$and" return q.AutoBindConditions(flag, value) } func (q *Query) Not(value interface{}) *Query { flag := "$not" return q.AutoBindConditions(flag, value) } func (q *Query) Gt(value interface{}) *Query { flag := "$gt" return q.AutoBindConditions(flag, value) } func (q *Query) Gte(value interface{}) *Query { flag := "$gte" return q.AutoBindConditions(flag, value) } func (q *Query) Lt(value interface{}) *Query { flag := "$lt" return q.AutoBindConditions(flag, value) } func (q *Query) Lte(value interface{}) *Query { flag := "$lte" return q.AutoBindConditions(flag, value) } func (q *Query) Ne(value interface{}) *Query { flag := "$ne" return q.AutoBindConditions(flag, value) } func (q *Query) In(value interface{}) *Query { flag := "$in" return q.AutoBindConditions(flag, value) } func (q *Query) Nin(value interface{}) *Query { flag := "$nin" return q.AutoBindConditions(flag, value) } func (q *Query) All(value interface{}) *Query { flag := "$all" return q.AutoBindConditions(flag, value) } func (q *Query) Regex(value interface{}) *Query { flag := "$regex" return q.AutoBindConditions(flag, value) } func (q *Query) Size(value interface{}) *Query { flag := "$size" return q.AutoBindConditions(flag, value) } func (q *Query) MaxDistance(value interface{}) *Query { flag := "$maxDistance" return q.AutoBindConditions(flag, value) } func (q *Query) MinDistance(value interface{}) *Query { flag := "$minDistance" return q.AutoBindConditions(flag, value) } func (q *Query) Mod(value interface{}) *Query { flag := "$mod" return q.AutoBindConditions(flag, value) } //TODO: geometry func (q *Query) Exists(value bool) *Query { flag := "$exists" return q.AutoBindConditions(flag, value) } func (q *Query) ElemMatch(value interface{}) *Query { flag := "$elemMatch" return q.AutoBindConditions(flag, value) } func (q *Query) bindCondition(value Input) *Query { q.conditions[q.field] = value return q } func (q *Query) resetField() *Query { q.field = "" return q } func (q *Query) setField(field string) *Query { q.field = field return q } func (q *Query) hasField() bool { if q.field == "" { return false } return true } func (q *Query) ensureField(method string) *Query { if q.field == "" { panic(method + " must be used after Where() ") } return q } func inputLogger(input Input) Input { go func() { fmt.Print(input) }() return input } func inputWrapper(flag string) InputEndpoint { return func(input Input) Input { return M{flag: input} } } func getFlagWrapperFromString(arg string) InputEndpoint { switch arg { case "<": return inputWrapper("$lt") case ">": return inputWrapper("$gt") case "=": return inputWrapper("$eq") case ">=": return inputWrapper("$gte") case "<=": return inputWrapper("$lte") default: return inputWrapper("$eq") } } func inputBuilder(input Input) Input { var res interface{} switch input.(type) { case func(q *Query): query := NewQuery() input.(func(q *Query))(query) res = query.conditions break case func(q *Query) *Query: res = input.(func(q *Query) *Query)(initQuery()).conditions break case interface{}: res = input break } return res } ``` |
21
linhongye 2021-10-24 15:14:47 +08:00
我们就是 Go+mongo, 舒服得很...
搞点插件熟练一下... |
22
balabalaguguji OP @linhongye #21 怎么会舒服,具体点怎么搞
|
23
balabalaguguji OP @Weny #20 感觉还是很复杂麻烦?
用你这个封装好的代码写一个查询用户 ID=1 的怎么查? 复杂点的 aggregate 怎么写,如下: pipline = [ {'$match': {'taskId': {'$in': taskIds}}}, {'$lookup': {"from": "groupLogs", "localField": "groupId", "foreignField": "_id", "as": "groupData"}}, {'$match': {'groupData': {'$size': 1}}}, {'$group': {'_id': '$taskId', 'count': {'$sum': '$totalCount'}}}, ] |
24
40EaE5uJO3Xt1VVa 2021-10-24 15:32:08 +08:00
@linhongye 怎么搞的请教一下
|
25
jim9606 2021-10-24 16:18:28 +08:00
你说的问题其实是强类型语言的问题,如果你对程序鲁棒性要求要一些,要对所有输入做格式和类型校验,那不可能优雅的。
go 里面任意类型的 map 是 map[string]interface{},不过访问这玩意的代码写起来也很烦就是了。 |
26
clf 2021-10-24 16:26:09 +08:00 via Android
java 的 mongo template 其实也是构建一个 Document 丢进去查询,mongo 官方基本就提供了连接和调用查询的基本方式,更多的还是由 orm 框架实现。
|
27
learningman 2021-10-24 16:26:14 +08:00
go 处理 json 就是不爽啊,想爽用 js
|
28
holulu 2021-10-24 16:37:51 +08:00
强类型都有这种问题,用过的语言多了,不同范畴的代码都写过了,就会看淡了。语言就是个工具,没必要看得那么重,大不了就换。
|
29
xnotepad 2021-10-24 16:52:05 +08:00
这应该是所有静态语言都有的问题。
|
30
Weny 2021-10-24 17:16:00 +08:00
@balabalaguguji 其实本质上就是一个 Map 的 builder
第一个问题 :queryBuilder.Where("user_id",id) aggregate 我觉得再封装一个 pipeline builder ,再扩展一下已有的 queryBuilder 比如 pipelineBuilder( queryBuilder.Match("taskId",func(q){return q.in(taskIds)}), queryBuilder.Lookup(func(q){return q.Form("")...}) ... ) |
31
gengchun 2021-10-24 17:25:48 +08:00
要静态语言,要性能就是这个结果。
可以找一些 orm ,我记得有的不需要传 context ;当然 orm 又会有性能问题,你对 orm 的一些选择也未必会满意。 |
32
xuanbg 2021-10-24 17:48:12 +08:00
自己再封装一下啊
|
33
TypeError 2021-10-24 18:17:44 +08:00
qmgo
|
34
xsen 2021-10-24 19:20:54 +08:00
这跟语言有什么关系,这只是 mongodb 的 sdk 没有封装好而已
都有参考的理想的用法,那自己再封装一层不就是可以 对于 flutter 嵌套这样的,对原有做 pc 客户端的(如 c++)的就很是友好 只是一个思维习惯的问题 |
35
zxCoder 2021-10-24 19:33:47 +08:00
感觉 mongodb 还是适合 js/ts
|
36
sunmoon1983 2021-10-24 19:36:27 +08:00
七牛的 qmgo
|
37
fireleaves 2021-10-24 19:50:27 +08:00
@balabalaguguji 试试这样一个 pipline 转 bson 接口呢?
```golang // MongoPipeline gets aggregation pipeline from a string func MongoPipeline(str string) mongo.Pipeline { var pipeline = []bson.D{} str = strings.TrimSpace(str) if strings.Index(str, "[") != 0 { var doc bson.D bson.UnmarshalExtJSON([]byte(str), false, &doc) pipeline = append(pipeline, doc) } else { bson.UnmarshalExtJSON([]byte(str), false, &pipeline) } return pipeline } ``` 这样调用 ```golang pipline = `pipline = [ {'$match': {'taskId': {'$in': taskIds}}}, {'$lookup': {"from": "groupLogs", "localField": "groupId", "foreignField": "_id", "as": "groupData"}}, {'$match': {'groupData': {'$size': 1}}}, {'$group': {'_id': '$taskId', 'count': {'$sum': '$totalCount'}}}, ]` opts := options.Aggregate() if res, err = collection.Aggregate(ctx, MongoPipeline(pipeline), opts); err != nil { t.Fatal(err) } ``` 参考自: https://github.com/simagix/mongo-go-examples |
38
Fitz 2021-10-24 20:54:56 +08:00
静态语言不都这样吗 无非是怎么封装,context 是为了并发控制, 这个没什么好喷的, 你只是没遇到需要它的场景
|
39
balabalaguguji OP @jim9606 #25 是这么回事,强类型的都得这么麻烦。
|
40
balabalaguguji OP @clf #26 看了下 Java 的,构建一个 Document 感觉比 Go 这种方式好很多,好接受多了
|
41
balabalaguguji OP @learningman #27 所以人生短暂,准备用 nodejs 吧,写起来舒服。
|
42
balabalaguguji OP @holulu #28 嗯,强类型确实没啥办法,不过 Java 的比 Go 的好很多,应该是有泛型的原因?(没怎么用过 JAVA)。
|
43
balabalaguguji OP |
44
balabalaguguji OP @sunmoon1983 #36 看了下,也是一堆包裹
|
45
YUyu101 2021-10-24 21:20:04 +08:00 1
确实不舒服,工作写了半年 go ,从没在工作用过的 nodejs 用起来无比丝滑,真是由俭入奢易,要是有一门语言把两者的优点合起来就好了。
|
47
zjsxwc 2021-10-24 22:24:15 +08:00 2
rust 有宏有泛型,比 go 好多了
https://github.com/mongodb/mongo-rust-driver#example-usage |
48
XTTX 2021-10-24 23:39:31 +08:00
JS 写成 typescript ,要写各式各样的 type\interface\generics, 可不必 Go 写 struct 方便多少。
|
49
XTTX 2021-10-24 23:45:50 +08:00
不清楚为什么贴主一定要用 mongoDB 。Go 写 psql query 挺方便的,写多了都是 boilerplate, 改改就差不多了
|
50
gengchun 2021-10-25 06:55:27 +08:00
@balabalaguguji 认真说起来的话。据说,动态里好像 erlang, groovy 这些强类型性能还可以,不过我都没有用过。我用过的里面,性能可以的确实都是静态的。主要是第一句看 python/js ,这个加上 golang 默认讨论的就是动态 vs. 静态,没仔细想就发了。
你的问题本身确实是 golang 的类型系统问题,但是 json 的这个的处理麻烦。并不是简单的需要静态检查,或者类型强弱导致的。如果只是强类型的话,但是有语法糖的话,其实也不会导致这样写。 不过语言设计太高深,还是打住,不然没完没了了。 总结一下,Golang 出于某个我不知道的原因,就是要让语言的用户,自己在业务代码层面上实现 hash 字典的处理。这么多年了,我估计默认的语法或者内置库,是不会有更方便的实现了。这个地方用 golang 不是自己封装,就是指着 orm ,也没有别的办法了。 |
52
vipppppp 2021-10-25 09:23:21 +08:00
MongoDB 官方的 Go 接口 真的,一言难尽。。。
|
53
p1gd0g 2021-10-25 09:24:37 +08:00
传 context 很正常吧。现在不传,以后有一天要用到再换函数?
|
54
airplayxcom 2021-10-25 09:35:05 +08:00 via iPhone
动态语言害人不浅
|
55
lizuoqiang 2021-10-25 09:35:15 +08:00
go 的 orm 真的一言难尽
|
56
pkoukk 2021-10-25 09:55:02 +08:00
动态语言害人不浅+1
别用 mongo 了,性能太差了,pg 吧 |
57
x940727 2021-10-25 10:04:42 +08:00
@holulu 不敢苟同,语言确实是工具,但是决定一个语言生命力的,语法不是关键性因素,语言附带的生态才是关键性因素。如果你换一个语言,就等于生态全部都需要重新去了解熟悉,这个沉没成本远比你想的要高的多,基本上没有老手会选择放弃自己钻研五六年的语言去换一个全新的语言,最多换一个相关性比较高的语言。我认为张嘴语言就是工具可以随便换的,不是超级大神,就是菜鸟……
|
58
qW7bo2FbzbC0 2021-10-25 10:14:00 +08:00
@Kisesy #15 mongodb 静态类型驱动本身就很捉急,更别提那种复杂 aggregate 操作转述时多么费力了。应该也可以输入 json str 自动转成 query document 的
|
59
rayw0ng 2021-10-25 10:20:04 +08:00
@pengtdyd Rust 官方例子,读起来很容易啊
use mongodb::{ bson::doc, sync::Client, }; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] struct Book { title: String, author: String, } let client = Client::with_uri_str("mongodb://localhost:27017")?; let database = client.database("mydb"); let collection = database.collection::<Book>("books"); let docs = vec![ Book { title: "1984".to_string(), author: "George Orwell".to_string(), }, Book { title: "Animal Farm".to_string(), author: "George Orwell".to_string(), }, Book { title: "The Great Gatsby".to_string(), author: "F. Scott Fitzgerald".to_string(), }, ]; // Insert some books into the "mydb.books" collection. collection.insert_many(docs, None)?; let cursor = collection.find(doc! { "author": "George Orwell" }, None)?; for result in cursor { println!("title: {}", result?.title); } |
60
lancelock 2021-10-25 10:22:42 +08:00 6
go 写业务本来就是残废。之前帮亲戚写了一个东西后就被我放弃了。但架不住跟风吹的多啊,中国人的权威崇拜深入骨髓,看着两个创世人的履历,和大公司的背景就不能自已了。凡是觉得不好用的,那一定是自己的问题,凡人不能领会大神的思维。动辄大道至简,你不懂 go 的哲学,可惜你的哲学也不是那么坚挺啊,这不就加上了泛型
关键 go 吹你吹就吹吧,还爱给你安利:来用 go 吧,你会打开新世界的大门。一副没有见识的样子,真实无语 |
61
wowbaby 2021-10-25 10:24:46 +08:00 1
我一般看到 .H .D .M 这的命名就没有了兴趣
|
62
keepeye 2021-10-25 10:32:22 +08:00
这是什么操作,mongodb 写的库垃圾,让 go 背锅?让一个静态语言跟脚本语言去比较所谓的 “优雅”也是醉了
|
63
xz410236056 2021-10-25 10:49:33 +08:00
“嗯,静态语言应该都是要先定义模型,太不灵活了。”
针对这句话问一下,动态语言不定义模型,后面接手的人知道你这个字典里有什么值吗?能直接点属性用吗?还是要写一堆字符串去取,万一再拼错了 |
64
shockerli 2021-10-25 11:55:38 +08:00
我用过,MongoDB 官方的 Go SDK 确实拉胯,但这不能算到 Go 语言身上
|
66
ila 2021-10-25 12:11:03 +08:00 via Android
@xz410236056 由得他去吹。
python 一样要定义模型再 crud. |
67
balabalaguguji OP @shockerli #64 那能找到一个更优雅的库?
|
68
chtcrack 2021-10-25 12:45:36 +08:00
真的要性能不如用 c 或者 c++,感觉用 go 怪怪的.https://docs.mongodb.com/drivers/cxx/
|
69
c88155745 2021-10-25 13:47:13 +08:00
MongoDB 有 go struct 约束 还是可以用的 ,反而弱类型语言容易类型出错 不同人整出各种类型
|
70
cyrivlclth 2021-10-25 13:47:25 +08:00
可以用 entgo 写一套模板,生成操作 MongoDB 库的代码。。。我之前刚准备弄这个,但是忙忘了
|
71
thevita 2021-10-25 13:48:31 +08:00
1. 如果觉得用 js python 直接读更舒服完全可以用 js.
2. 没受过动态类型荼毒的,必然难以理解强类型系统的作用 3. 强类型与否, 看自己的 use case 吧这个不好说,有的场景就是用 js 写着就很爽,矫枉过正还是不好,被毒打多了就逐渐知道怎么平衡了 4. mongo 本来就是个文档数据库,半结构化,天然跟 js ,python 之类的会亲和一点 5. 应该能通过合理的约定+时代的封装 /抽象 来缓解,就是谨慎点用 mongo ,模式管理更规范一点(当然,并不是说你不规范的意思,只是说到这里了) 6. 写 go 踩到自己的地方多了去了,老想给自己一拳。 |
73
XTTX 2021-10-25 14:36:48 +08:00
从 mongoDB 和 Go 的不匹配到讨伐 Golang ,这出戏我见过了。每个语言都有自己存在的理由。用不用得习惯,适不适合自己的使用场景,得看自己。js 为了类型检查,搞出了 typescript. 都用习惯了就好了,没有完美的语言和工具
|
74
thtznet 2021-10-25 14:40:04 +08:00
C# 欢迎你,不极端,兼容各类语言的优点,集大成者。
|
76
skiy 2021-10-25 15:09:28 +08:00
可以等等试试泛型出来之后?
|
78
zhuangzhuang1988 2021-10-25 15:22:55 +08:00
@thtznet 能听就好了
|
79
x940727 2021-10-25 15:41:31 +08:00
@holulu 如果写小工具的话,那无所谓生态问题,毕竟现在大部分语言的标准库都不差,我平时也会用 Python 和 Go 写一些数据处理、系统小脚本之类的,但是如果是写复杂点的项目,生态的重要性就凸显出来了。
|
80
zjyl1994 2021-10-25 15:42:56 +08:00
我也觉得交互很傻,所以我放弃了 mongo 。个人觉得 mongo 没香到哪里去
|
81
qq1340691923 2021-10-25 15:44:09 +08:00
我刚开始也是用的官方库,怎么写怎么繁琐,后来换成了 https://github.com/go-mgo/mgo ,瞬间开发效率都高了好多
|
82
gowk 2021-10-25 15:59:14 +08:00
@lancelock 目前业务密集型应用就别用 Go 了,给自己找麻烦,好好用 Java 挺香。但是我挺期待 Go 泛型的大规模应用,再加上完备的库和生态,让写业务也成为一种乐趣。
|
83
qq1340691923 2021-10-25 16:07:54 +08:00
golang 官方的 es 库用起来也没有第三方的库清爽
|
84
securityCoding 2021-10-25 16:10:27 +08:00
@gowk 没泛型写业务是真的操蛋
|
86
solos 2021-10-25 17:48:18 +08:00
你该放弃的是 mongodb
|
87
holulu 2021-10-25 18:14:21 +08:00
@x940727 现在微服务的优势就可以让你结合不同工具的优势来打造复杂的项目,减少要在同一个项目中使用统一的技术框架的麻烦。
|
88
x940727 2021-10-25 18:21:34 +08:00
@holulu 微服务的副作用是非常大的,上分布式系统的前提就是能不上分布式就别上,如果我就是业务复杂但是用户量不大呢?软件工作没有银弹,微服务也不是架构银弹。
|
89
xiaotianhu 2021-10-25 19:06:22 +08:00
@x940727 不敢苟同,语言确实是工具,但是决定一个语言生命力的,语法不是关键性因素,语言附带的生态才是关键性因素。如果你换一个语言,就等于生态全部都需要重新去了解熟悉,这个沉没成本远比你想的要高的多,基本上没有老手会选择放弃自己钻研五六年的语言去换一个全新的语言,最多换一个相关性比较高的语言。我认为张嘴语言就是工具可以随便换的,不是超级大神,就是菜鸟……
大神都是不用干活搞科研那种,研究点编译原理 runtime 什么的,才不要解析神马 JSON ,太 low |
90
x940727 2021-10-25 19:13:18 +08:00
@xiaotianhu 那也不一定啊,就拿软件领域来说,搞科研的很多东西落不了地,你看 MIT 的莫里斯教授对于 Hadoop 就赞扬有加,因为这玩意是落了地的,验证了可行性并且大规模使用的。大部分理工科人还是不喜欢嘴炮侠的吧。
|
91
Z1on 2021-10-25 20:25:19 +08:00
@XTTX mongo.Connect()在程序启动的时候,放在 init 里面调用一次就好了,把 client 声明成全局变量。client 是并发安全的,会自己维护一个链接池。
https://github.com/mongodb/mongo-go-driver/blob/v1.7.3/mongo/client.go#L51 |
92
gengchun 2021-10-25 23:38:47 +08:00
@lancelock 这个是工业化,和权威没有关系。Golang 的目标和之前 Java 一样,就是希望高中毕业培训两个月,给个最低工资就能上手写代码。
真能单枪匹马完成项目,想用 lisp 都没有人管。 |
93
holulu 2021-10-26 07:07:54 +08:00
@x940727 不是说微服务就能解决所有问题,只是提供一个思路或方向。任何技术都有副作用,大不大看能否承受,重要的是权衡利弊。软件工程就是风险管理,永远不可能为要实现的业务找到最合适的技术方案,只有在不同方案之间妥协,寻找一个适应当时业务发展的平衡点。了解的技术越多,离找到合适的平衡点就越近。
|
94
tiedan 2021-10-26 09:13:42 +08:00
可能我用习惯了,我觉得 go 下操作 mongo 挺方便的😂
|
95
wildlife 2021-10-27 09:47:20 +08:00
|
96
balabalaguguji OP @wildlife #95 瞬间感觉 mongodb 如此复杂
|
97
8355 2021-10-27 14:39:31 +08:00
用 php 啊 一把嗦 不要考虑这些 拥抱世界上最好的语言 狗头
|
98
darknoll 2021-10-28 17:06:29 +08:00
不能拿静态语言和动态语言比,你要觉得 go 麻烦,那 C++看都不能看了啊
|