search
LoginSignup
10
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

MongoDB.com公式Goドライバを使った基本操作

Mgoを使った例は結構あるのだけど、MongoDB.comの公式ドライバを使った例があまりないなと思い、未来の自分のために書き残しておく。タグはStackOverflowに合わせmongo-go としてみた。

今回のソースコード一式はhttps://github.com/mkiuchi/go-mongo-driver-exampleに置いておきました。

Mgoと公式ドライバの違いとか情報源とか

調べてないのでよくわからない。公式でも若干触れられてるけどあまりこのへんをどうこう言う気はないので気になる人は各自なんとかしてください。

公式ドライバについてはMongoDB.comのドライバページを見る。記事執筆時点の最新バージョンは 1.0.3。たぶん最もよく見るのはGoDoc, チュートリアルだとは思うんだけど、いまいち詳細さに欠けていて、これを見てもわかるようなわからないようなイマイチわかりきらないところがある。この記事を書くことにした理由の一つ。

上でも書いたけど、公式以外で私が見た限りではStackOverflowが情報源としては一番ある。あるけどほとんど会話がなく、正直あてにならない。各自頑張ってください。

インストール

公式のとおりにすれば入る。私の場合は dep が動かなかったので go get で入れた。

$ dep ensure -add "go.mongodb.org/mongo-driver/mongo@~1.0.0"
$ go get -u "go.mongodb.org/mongo-driver/mongo"
$ go get "go.mongodb.org/mongo-driver/bsontype"

接続

以下のようにする。以下の例ではデータベースへの接続をチェックして、結果を出力する。

connect.go
package main

import (
    "context"
    "fmt"
    "time"

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

func main() {
    // コンテキストの作成
    //   - バックグラウンドで接続する。タイムアウトは10秒
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    // 関数を抜けたらクローズするようにする
    defer cancel()
    // 指定したURIに接続する
    c, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
    defer c.Disconnect(ctx)
    // DBにPingする
    err = c.Ping(ctx, readpref.Primary())
    if err != nil {
        fmt.Println("connection error:", err)
    } else {
        fmt.Println("connection success:")
    }
}

接続オプションはだいたいどの記事でも context.Background() が使用されているけど、例によっては context.TODO() も使用されていることがある。とりあえず context.Background() を使用しておけばいいと思う。

読み出し

単純に検索して1件読み出す

readone.go
package main

import (
    "context"
    "fmt"
    "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"
)

func main() {
    // MongoDBの接続設定
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    c, _ := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
    defer c.Disconnect(ctx)

    // 結果を格納する変数の構造定義
    type resultType struct {
        Rid     string
        Keyword string
    }

    // 結果を格納する変数を宣言
    var result resultType

    // MongoDBのCollectionを取得
    col := c.Database("rec").Collection("autorec")

    // 検索条件となるprimitive.ObjectID型の変数を指定
    objectID, _ := primitive.ObjectIDFromHex("5cffa613c74a91322fc7cbb2")

    // 検索を実行し、結果を変数 result に格納
    err := col.FindOne(context.Background(), bson.M{"_id": objectID}).Decode(&result)
    _ = err
    fmt.Println(result)
}

結果は以下のような感じになる

$ go run readone.go 
{abcd1234 オリンピック}

複数の検索結果を読み出す

readmany.go
package main

import (
    "context"
    "fmt"
    "time"

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

func main() {
    // MongoDBの接続設定
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    c, _ := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
    defer c.Disconnect(ctx)

    // 結果を格納する変数の構造定義
    type resultType struct {
        Start int
        Title string
    }

    // MongoDBのCollectionを取得
    col := c.Database("rec").Collection("rec")

    // 検索条件となるint型の変数を指定
    location, _ := time.LoadLocation("Asia/Tokyo")
    start := time.Date(2019, 6, 30, 0, 0, 0, 0, location).Unix() * 1000
    end := time.Date(2019, 6, 30, 23, 59, 59, 99, location).Unix() * 1000
    fmt.Println(start, end)

    // 検索を実行
    cur, err := col.Find(context.Background(), bson.M{
        "start": bson.M{
            "$gte": start,
            "$lte": end,
        }})
    _ = err

    // 結果のカーソルをforで回して順番に結果を取得
    for cur.Next(context.Background()) {
        var ret resultType
        cur.Decode(&ret)
        fmt.Println(ret)
    }
}

結果は以下のようになる

$ go run readmany.go 
1561820400000 1561906799000
{1561879320000 プレマップ}
{1561880460000 フラッシュ天気}

ドキュメント(=レコード)の挿入

insert.go
package main

import (
    "context"
    "time"

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

func main() {
    // MongoDBの接続設定
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    c, _ := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
    defer c.Disconnect(ctx)

    // 挿入するデータの構造を定義
    // 21, 22行目の末尾の文字はType aliasと呼ぶらしい。MongoDB内でフィールド名として解釈される
    type dataType struct {
        Rid     string `bson:"rid"`
        Keyword string `bson:"keyword"`
    }

    // 挿入するデータを作成
    data := dataType{
        Rid:     "俺のID",
        Keyword: "俺のキーワード",
    }

    // MongoDBのCollectionを取得
    col := c.Database("rec").Collection("autorec")

    // データを挿入
    col.InsertOne(context.Background(), data)

}

上記の例では構造体(struct)を挿入しているが、他の型(例えばmapとか)を直接突っ込んでも割とよろしく取り扱ってくれる

複数データのバルク挿入はまだやったことがないのでスキップ。

ドキュメント(=レコード)の削除

delete.go
package main

import (
    "context"
    "fmt"
    "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"
)

func main() {
    // MongoDBの接続設定
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    c, _ := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
    defer c.Disconnect(ctx)

    // MongoDBのCollectionを取得
    col := c.Database("rec").Collection("autorec")

    // 検索条件となるprimitive.ObjectID型の変数を指定
    objectID, _ := primitive.ObjectIDFromHex("5d1924916a81c3556cf3479b")

    // 検索を実行し、結果のドキュメントを削除
    _, err := col.DeleteOne(context.Background(), bson.M{"_id": objectID})
    if err != nil {
        fmt.Println("delete failed:", err)
    } else {
        fmt.Println("delete success")
    }
}

特にコメントなし。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
10
Help us understand the problem. What are the problem?