使用Golang的MongoDriver和reflect包来获取数据的方法是什么?
package main
import (
"context"
"fmt"
"log"
"reflect"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
type Foo struct {
ID *primitive.ObjectID `json:"_id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
}
func main() {
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
ctx, _ = context.WithTimeout(context.Background(), 2*time.Second)
if err = client.Ping(ctx, readpref.Primary()); err != nil {
log.Fatalf("%+v\n", err)
}
collection := client.Database("testing").Collection("foo")
// ここまでサンプルどおり ---------------------------------
fooType := reflect.TypeOf(Foo{})
fooSlice := createSlice(reflect.SliceOf(fooType))
// この行がメイン
d := find(collection, fooSlice, fooType).([]Foo)
fmt.Println(d)
}
// 黒魔術感ある
// 単純にMakeSliceだけだと到達可能なアドレスを返せないので、makedSlice.CanSet() == false
// なので、新しくreflect.valueをNewして、作ったmakedSliceをセットする形を取っている。
func createSlice(sliceType reflect.Type) reflect.Value {
makedSlice := reflect.MakeSlice(sliceType, 0, 16)
reflectionValue := reflect.New(makedSlice.Type())
reflectionValue.Elem().Set(makedSlice)
slicePtr := reflect.ValueOf(reflectionValue.Interface())
return slicePtr.Elem()
}
func find(col *mongo.Collection, reflectSlice reflect.Value, reflectType reflect.Type) interface{} {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
cur, err := col.Find(ctx, bson.M{})
if err != nil {
log.Fatalf("%+v\n", err)
}
defer cur.Close(ctx)
for cur.Next(ctx) {
v := reflect.New(reflectType)
if err := cur.Decode(v.Interface()); err != nil {
log.Fatalf("%+v\n", err)
}
reflectSlice.Set(reflect.Append(reflectSlice, v.Elem()))
}
if err := cur.Err(); err != nil {
log.Fatalf("%+v\n", err)
}
return reflectSlice.Interface()
}
如果使用Mongo数据库或者进行数据准备,虽然需要一些步骤,但如果使用Golang 1.12以上版本,只需复制黏贴即可运行。
不过话说回来,Golang的反射真的很难理解和使用。
听说有引入范型的计划,如果实现了,就不用写这种代码了,感觉真不错呢。
在性能方面,-试了使用1万条数据进行查找的情况下,
-
型指定:55ms
リフレクション:58ms
因为差别只有大约3毫秒左右,所以应该可以使用,不是吗?
此外,关于createSlice函数的具体内容,为什么必须这样做才能使其正常工作?我还没有完全理解。。。
※2019年06月17日追記:我写了一篇文章,旨在深入理解黑魔法代码。
https://qiita.com/daijinload/items/f822e4a208d17e432599