我尝试使用mongoDB的Go驱动程序

概括

(概要)

我接触了适用于Go的MongoDB官方驱动程序,以下是我的总结。

环境

使用中文将以下内容进行释义,只需要一个选项:
go 1.12.5
go.mongodb.org/mongo-driver v1.1.2
mongoDB 3.1

使用的詞彙

有一位能够简明易懂地总结的人

    • table → collection

 

    • row → document

 

    column → field

连接

不过,我觉得查看公式文件的使用说明可能更快一些。

import (
    "context"
    "log"

    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://username:password@localhost:27017"))
    if err != nil {
        log.Fatalln(err)
        return
    }
}

在這裡指定連接的URI為「mongodb://username:password@localhost:27017」。

找一个

如果使用结构体创建搜索条件,获取文档。

import (
    "go.mongodb.org/mongo-driver/bson/primitive"
    // NOTE: 他に必要なパッケージは省略
)

type FindOneRequest struct {
    // NOTE: 検索したいfieldとvalueを適宜定義する
    TargetField string `json:"targetField" bson:"targetField"`
}

type FindOneResponse struct {
    ID              primitive.ObjectID `json:"id" bson:"_id"`
    Hoge            string             `json:"hoge" bson:"hoge"`
    Fuga            string             `json:"fuga" bson:"fuga"`
}

func main() {
    // NOTE: 接続処理は省きやす 上の見てくだされ

    collection := client.Database("db_name").Collection("collection_name")

    request := FindOneRequest{
        TargetField: "検索内容",
    }

    var response FindOneResponse
    err = collection.FindOne(context.Background(), request).Decode(&response)
    if err == mongo.ErrNoDocuments {
        log.Println("Documents not found")
    } else if err != nil {
        log.Fatalln(err)
    }

    log.Println(res)
}

如果使用结构体,可以使用bson标签来指定在文档中使用的字段名称,从而进行合适的映射。
当创建文档时,使用primitive.ObjectID类型可以自动生成ObjectID,非常方便。

找到

获取多个文档
这次我们使用bson.D来定义搜索条件,并使用bson.M作为响应。

import (
    "go.mongodb.org/mongo-driver/bson"
    // NOTE: 他に必要なパッケージは省略
)

func main() {
     // NOTE: 接続処理は省きやす

    collection := client.Database("db_name").Collection("collection_name")

    // NOTE: 検索したいfield名とvalueを定義
    cur, err := collection.Find(ctx, bson.D{{Key: "field_name", Value: "value"}})
    if err != nil {
        log.Fatal(err)
    }
    defer cur.Close(ctx)
    for cur.Next(ctx) {

        // NOTE: 1ドキュメントずつdecode
        //       mapが返ってくる
        var result bson.M
        err := cur.Decode(&result)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(result)
    }
    if err := cur.Err(); err != nil {
        log.Fatal(err)
    }
}

当使用Find时,返回值并不是简单的数组等,而是返回了Cursor类型,所以我感觉处理起来很特别。

插入一个

添加文档

import (
    "go.mongodb.org/mongo-driver/bson/primitive"
    // NOTE: 他に必要なパッケージは省略
)

type InsertOneRequest struct {
    ID              primitive.ObjectID `json:"id" bson:"_id"`
    Hoge            string             `json:"hoge" bson:"hoge"`
    Fuga            string             `json:"fuga" bson:"fuga"`
}

func main() {
    // NOTE: 接続処理は省きやす

    collection := client.Database("db_name").Collection("collection_name")

    request := InsertOneRequest{
        ID: primitive.NewObjectID(),
        Hoge: "hoge",
        Fuga: "fuga",
    }

    // NOTE: InsertOneの返り値には作成したドキュメントのObjectIDが返ってくる
    response, err := collection.InsertOne(context.Background(), request)
    if err != nil {
        log.Fatalln(err)
    }
}

当您希望使用创建的文件进行某些操作时,可以使用request.ID通过FindOne函数获取相应的结构体来实现。

插入多个

注册多个文件

import (
    "go.mongodb.org/mongo-driver/bson/primitive"
    // NOTE: 他に必要なパッケージは省略
)

type Request struct {
    ID              primitive.ObjectID `json:"id" bson:"_id"`
    Hoge            string             `json:"hoge" bson:"hoge"`
    Fuga            string             `json:"fuga" bson:"fuga"`
}

func main() {
    // NOTE: 接続処理は省きやす

    collection := client.Database("db_name").Collection("collection_name")

    var insertManyRequest []interface{}

    for index := 0; index < 10; index++ {
        indexString := strconv.Itoa(index)

        request := Request{
            ID:   primitive.NewObjectID(),
            Hoge: "hoge",
            Fuga: "fuga",
        }

        insertManyRequest = append(insertManyRequest, question)
    }

    // NOTE: 今回の場合、一括で10件登録してくれる
    //       返り値はinsertしたドキュメントのObjectIDの配列
    response, err := collection.InsertMany(context.Background(), insertManyRequest)
    if err != nil {
        log.Fatalln(err)
    }
}

InsertMany方法的第二个参数是[]interface{}类型。

汇总

似乎可以使用Aggregate来进行集合计算。
在mongoDB中,有一种叫作Operators的东西,可以通过使用这些Operators来对Collection进行操作。

在Operators中,Pipeline是用于Aggregate的。
在官方文档中有相对较多的示例,如果参考那些示例,就可以不知不觉地进行实施。

import (
    "go.mongodb.org/mongo-driver/bson"
    // NOTE: 他に必要なパッケージは省略
)

func main() {
    // NOTE: 接続処理は省きやす

    collection := client.Database("db_name").Collection("collection_name")

    pipeline := []bson.M{
        bson.M{
            "$match": bson.M{
                "targetField": "value",
            },
        },
        bson.M{
            "$group": bson.M{
                "_id": "$targetFieldID",
                "count": bson.M{
                    "$sum": 1,
                },
            },
        },
    }

    // NOTE: AggregateはFindと同様に`*Cursor`型を返すので、Cursor型用の扱い方が必要
    hogeAggre, err := collection.Aggregate(ctx, pipeline)
    if err != nil {
        log.Fatalln(err)
    }

    defer hogeAggre.Close(ctx)

    for hogeAggre.Next(ctx) {
        var result bson.M
        err := answerAggre.Decode(&result)
        if err != nil {
            log.Fatal(err)
        }

        fmt.Println(result)
    }
    if err := answerAggre.Err(); err != nil {
        log.Fatal(err)
    }
}

预期的输出结果应该是返回类似下面所示的结果
由于可能严谨地说会有所不同,请勿见怪

[
    {
        "_id": "hogehoge",
        "count": 15,
    },
    {
        "_id": "fugafuga",
        "count": 13,
    },
]

有一个带有$符号的是Operator对吧。这次在Pipeline里指定的是通过Collection名为collection_name的targetField字段的值为value的文档们,按照targetFieldID字段进行分组,计算每个targetFieldID的文档数量,并将结果存储在count字段中。大概是这样吧。

操作员和管道阶段等需要更多阅读文档的可能性较高。

感受

当进行Insert或Find操作时,参数和返回值都应当通过结构体进行明确定义。然而,由于文档的结构即使是相同的集合也可能有不同的可能性,所以或许不应该像bson.M那样进行严格的类型定义,这也是一种选项。

广告
将在 10 秒后关闭
bannerAds