Go Mongo Driver

Table of Contents

以下内容均基于 Go MongoDB Client: go.mongodb.org/mongo-driver

1 interface{} decode to bson.M

业务场景是这样的:在插入 MongoDB 时,会插入一个前端给的 JSON,而后端对 JSON 的具体格式并不确定,希望怎么插入就怎么输出。 所以,后端(Go)就声明成了一个 interface{} ,insert 之后没有任何问题,在 MongoDB 中存储的也达到了期望。

但是在查询时,发现返回的值并不是插入的 JSON,而被拆解成了 {"Key": "xxx", "Value": "yyy"} 这种方式,而实际上的格式是: {"xxx": "yyy"}

有人给 MongoDB 提过 issue, https://jira.mongodb.org/browse/GODRIVER-988 ,问题是相同的。解决办法是:在初始连接 MongoDB 的时候设置解析方式,

tM := reflect.TypeOf(bson.M{})
reg := bson.NewRegistryBuilder().RegisterTypeMapEntry(bsontype.EmbeddedDocument, tM).Build()
client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri).SetRegistry(reg))

查看 RegisterTypeMapEntry 的定义,发现在它已经在注释中说明了解析逻辑:

// RegisterTypeMapEntry will register the provided type to the BSON type. The primary usage for this
// mapping is decoding situations where an empty interface is used and a default type needs to be
// created and decoded into.
//
// By default, BSON documents will decode into interface{} values as bson.D. To change the default type for BSON
// documents, a type map entry for bsontype.EmbeddedDocument should be registered. For example, to force BSON documents
// to decode to bson.Raw, use the following code:
//  rb.RegisterTypeMapEntry(bsontype.EmbeddedDocument, reflect.TypeOf(bson.Raw{}))
func (rb *RegistryBuilder) RegisterTypeMapEntry(bt bsontype.Type, rt reflect.Type) *RegistryBuilder {
    rb.typeMap[bt] = rt
    return rb
}

默认情况下,BSON 文档的 interface{} 值是 bson.D ,即 bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}} 这种一对一对的形式。 而我们期望的是 bson.M ,格式是 bson.M{"foo": "bar", "hello": "world", "pi": 3.14159} 。所以改成 bson.M 就可以了。

如果希望是字节流的话,可以改成 bson.Raw{}

2 分页、排序

MongoDB 在查询时的选项都是有 FindOptions 控制的。分页通过 FindOptionsSkipLimit 来实现:

  • Limit 表示当前页的大小
  • Skip 表示跳过多少个元素

排序通过 Sort 来实现。整体如下:

options.Find().SetSkip(skip).SetLimit(limit).SetSort(bson.M{"create_timestamp": -1})

3 只取 Document 中的一部分

很多时候,把 Document 中的所有的字段全部取出来性能是很低下的,而且真实的业务场景也是需要其中的部分字段。

FindOptions 中的 Projection 是用来限制查询返回的字段的,默认值为 nil,即全部。 true 表示字段显示,反之 false 表示不显示。

如: options.Find().SetProjection(bson.M{"timestamp": true}) 表示只显示返回 timestamp 字段(返回的结构依然是存储的结构,只不过其它的字段全部为 nil)。

First created: 2020-06-29 14:43:51
Last updated: 2020-08-10 Mon 14:36
Power by Emacs 26.3 (Org mode 9.3.7)