Go With MongoDB 2

11276 ワード

  • に挿入する埋め込まれたdocumentと関係型データベースの最大の違いは、documentデータベース(非関係型データベース)がモデル化されたオブジェクトの関係アクセスをサポートしないことである.リレーショナル・データベースでは、親テーブルと子テーブルを使用する連絡先を作成し、親テーブルの各レコードが子テーブルの複数のレコードに関連付けられる.このようなデータ上の対応のために、サブテーブルに追加のkey値が親テーブルのprimary keyを指すことを定義する必要がある.

  • MongoDBはより柔軟な構造を持っている.したがって、データモデルは、同じオブジェクトを取得することを異なる方法で定義することができる.アプリケーションのコンテキストに基づいて正しいモードを選択してデータモデルを定義することができます.リンクデータの関係を確立するためには、主なdocumentにdocumentを埋め込むか、2つのdocument間で参照することができる.この両者の応用状況は実際の状況に応じて応用する.
    以下の例は、リンクデータの関係を記述するために埋め込まれたdocumentを用いるデータモデルを示す.CategoryとTaskデータの連絡Categoryには複数のTaskエンティティがある.
    // mongodb
    package main
    
    import (
        "log"
        "time"
    
        "gopkg.in/mgo.v2"
        "gopkg.in/mgo.v2/bson"
    )
    
    type Task struct {
        Description string
        Due         time.Time
    }
    
    type Category struct {
        Id          bson.ObjectId `bson:"_id,omitempty"`
        Name        string
        Description string
        Tasks       []Task
    }
    
    func main() {
        session, err := mgo.Dial("localhost")
        if err != nil {
            panic(err)
        }
        defer session.Close()
    
        session.SetMode(mgo.Monotonic, true)
        //      
        c := session.DB("taskdb").C("categories")
    
        //
        doc := Category{
            bson.NewObjectId(),
            "Open-Source",
            "Task for open-source prijects",
            []Task{
                Task{"Create project in mgo", time.Date(2016, time.May, 10, 0, 0, 0, 0, time.UTC)},
                Task{"Create REST API", time.Date(2016, time.May, 20, 0, 0, 0, 0, time.UTC)},
            },
        }
    
        err = c.Insert(&doc)
        if err != nil {
            log.Fatal(err)
        }
    
    }
    
    

    Task要素タイプの配列を含むCategory構造体が作成された.ドキュメントの埋め込みは、親ドキュメントと関連するサブドキュメントを取得することができ、クエリーを1回だけ行う必要があります.
  • 文書
  • を読み取る.
    CollectionのFindメソッドでは、MongoDBのcollectionsをクエリーできます.このメソッドを呼び出すと、collectionデータをフィルタするドキュメントを提供することができる.Findメソッドはdocumentを使用してクエリを行う.documentクエリーcollectionを提供するには、map、struct値などのBSONデータにシーケンス化可能なオブジェクトを提供する必要がある.
  • すべてのレコードを検索Findメソッドのパラメータがnilの場合collectionのすべてのdocumentを検索する.次の例は、上記の例が保存するすべてのdocument
  • を検索する例である.
    iter := c.Find(nil).Iter()
        result := Category{}
    
        for iter.Next(&result) {
            fmt.Printf("Category:%s,decription:%Ss
    ", result.Name, result.Description) tasks := result.Tasks for _, v := range tasks { fmt.Printf("Task:%s Due:%s
    ", v.Description, v.Due) } } if err = iter.Close(); err != nil { log.Fatal(err) }

    Iterメソッドはdocumentsを列挙するために使用される.Iterはクエリーを実行し、列挙可能なすべての値を得る.documentに親子関係が埋め込まれている場合、クエリー文でアクセスできます.
  • ソートレコード
  • DocumentsはSortメソッドでソートすることができる.Sortメソッドは、提供するフィールドに従ってソートする.
        //sort
        iter := c.Find(nil).Sort("name").Iter()
        
        for iter.Next(&result) {
            fmt.Printf("Category:%s,decription:%Ss
    ", result.Name, result.Description) tasks := result.Tasks for _, v := range tasks { fmt.Printf("Task:%s Due:%s
    ", v.Description, v.Due) } } if err = iter.Close(); err != nil { log.Fatal(err) }

    フィールドに基づいて逆ソートする場合は、フィールド名に「-」を付けるだけです.
        iter := c.Find(nil).Sort("-name").Iter()
    
    
  • 単一レコード
  • を取得する.
     result := Category{}
     err := c.Find(bson.M{"name":"Open-Source"}).One(result)
     if err != nil{
         log.Fatal(err)
     }
     
     fmt.Printf("Category:%s,Description:%s
    ",result.name,result.Description) task := result.Tasks for _,v := range tasks{ fmt.Printf("Task:%s Due:%v
    ",v.Description,v.Due) }

    bson.M(M->map)タイプは、データの問合せに用いる.ここで、nameフィールドを使用してcollectionをクエリーします.Oneメソッドはクエリを実行するresultに解析する.もう1つのFindIdメソッドは、単一のデータのクエリーをより便利にする.idクエリcollectionで対応するdocumentを直接使用
    query := c.Find(bson.M{"_id":id})
    
    
    result := Category{}
    err = c.FindId(obj_id).One(&result)
    
    
  • 更新クエリ操作
  • Updateメソッドはdocumentのデータを更新することができる.
    func (c *Collection) Update(selectorinterface{},updateinterface{}) error
    
    

    Updateメソッドはcollectionからdocumentを検索、提供するセレクタで検索し、提供するdocumentで更新する.一部の更新は「%set」キーを使用してdocumentを更新することができる.
        //update a document
        err := c.Update(bson.M{"_id": id},
            bson.M{"$set":bson.M{
                "description":"Create open-source projects",
                "tasks":[]Task{
                    Task{"Evaluate Negroni Project", time.Date(2015, time.August, 15, 0, 0, 0,
                          0, time.UTC)},
                    Task{"Explore mgo Project", time.Date(2015, time.August, 10, 0, 0, 0, 0,
                          time.UTC)},
                    Task{"Explore Gorilla Toolkit", time.Date(2015, time.August, 10, 0, 0, 0, 0,
                          time.UTC)},
                },
                
            }}
        )
    
    

    部分更新:descriptionとtasks.Updateメソッドは、提供するidに基づいて検索を行い、その後、対応するフィールドを変更し、提供するdocumentの対応する値を書き込む.
  • document
  • を削除
    Removeメソッドはcollectionからdocumentを削除することができる.RemoveAllメソッドはすべてのdocumentを削除し、パラメータがnilの場合はc.RemoveAll(nil)をすべて削除します.
    func (c *Collection) Remove(selector interface{}) error //err := c.Remove(bson.M{"_id": id})
    
    func (c *Collection) RemoveAll(selector interface{}) (info *ChangeInfo, err error)
    
    
    

    MongoDBの下付き索引
    MongoDBデータベースとリレーショナルデータベースは、効率的な読み取り操作を行うため、MongoDBデータベースをよりよく操作するために、collectionにインデックスを追加することで効率を提供することもできる.collectionのインデックスは、効率的なクエリー操作を行うことができる.MongoDBは、collectionレベルでインデックスを定義するもよいし、collection張documentまたは任意のフィールドでインデックスを定義してもよい.
    すべてのcollectionはデフォルトで1つあります.idフィールドのため.このフィールドを定義しないと、MongoDBプロセスは自動的に_を作成します.idフィールド、値タイプはObjectId.idインデックスは一意です.
    フィルタ動作を頻繁に使用してcollectionsをクエリーする場合は、インデックスを使用してより良い操作を検討する必要があります.mgoデータベース駆動はEnsureIndex方法を提供し、インデックスを作成し、パラメータはmgoである.Indexタイプ
    例:
    // mongodb
    package main
    
    import (
        "fmt"
        "log"
        "time"
    
        "gopkg.in/mgo.v2"
        "gopkg.in/mgo.v2/bson"
    )
    
    type Task struct {
        Description string
        Due         time.Time
    }
    
    type Category struct {
        Id          bson.ObjectId `bson:"_id,omitempty"`
        Name        string
        Description string
        //Tasks       []Task
    }
    
    func main() {
        session, err := mgo.Dial("localhost")
        if err != nil {
            panic(err)
        }
        defer session.Close()
    
        session.SetMode(mgo.Monotonic, true)
        //      
        c := session.DB("taskdb").C("categories")
        c.RemoveAll(nil)
    
        //index
        index := mgo.Index{
            Key:        []string{"name"},
            Unique:     true,
            DropDups:   true,
            Background: true,
            Sparse:     true,
        }
    
        //create Index
        err = c.EnsureIndex(index)
        if err != nil {
            panic(err)
        }
    
        //     
        err = c.Insert(&Category{bson.NewObjectId(), "R & D", "R & D Tasks"},
            &Category{bson.NewObjectId(), "Project", "Project Tasks"},
            &Category{bson.NewObjectId(), "Open Source", "Tasks for open-source projects"})
    
        if err != nil {
            panic(err)
        }
    
        result := Category{}
        err = c.Find(bson.M{"name": "Open-Source"}).One(&result)
        if err != nil {
            log.Fatal(err)
        } else {
            fmt.Println("Description:", result.Description)
    
        }
    
    

    mgoを作成しました.Index,メソッドEnsureIndexメソッドが呼び出された.IndexタイプのKey属性は、1つのスライスをフィールド名として使用することができる.ここでnameフィールドはindexとして使用する.フィールドはスライスであるため、インスタンスIndexに複数のフィールドを提供することができる.Uniqueプロパティは、1つのdocumentに1つのindexがあることを確認します.デフォルトのindexは昇順です.降順が必要な場合は、フィールドの前に「-」を付けることができます.
    key : []string{"-name"}
    
    
  • session DialメソッドとMongoDBデータベースを管理するリンクを確立するとmgoが返される.Sessionオブジェクトは、このオブジェクトを使用してすべてのCRUD操作を管理することができ、sessionはMongoDBサーバ群のリンクプールを管理する.1つのリンクプールはデータベースリンクのキャッシュであるため、新しい要求リンクデータベースの操作が使用済みリンクを再利用する.そのため、ウェブアプリケーションを開発する場合、単一のグローバルなSessionペアを用いてすべてのCRUD操作を行うことは非常に悪い.

  • 推奨されるsessionオブジェクトの管理プロセス:1.Dialメソッドを使用してセッションオブジェクトを取得する.2.独立したHTTPリクエストのライフサイクルにおいて、New、CopyまたはCloneメソッドを使用してセッションを作成すると、Dialメソッドによって作成されたセッションが取得する.これにより接続プール内のセッションオブジェクトを正しく使用することができる.3.HTTPリクエストのライフサイクルにおいて、取得したセッションオブジェクトを用いてCRUD操作を行う.
    Newメソッドは、同じパラメータを持つ新しいSessionオブジェクトを作成します.CopyメソッドはNewメソッドと同様に動作するが、copyはセッションの元の情報を保持する.CloneメソッドはCopyと同じですが、元のSesssionのsocketから
    次の例は、HTTPサーバがcopyを使用するセッションオブジェクトである.1つのstructタイプはSessionオブジェクトを持っていて、要求されたHandlerの中で非常に簡単にデータベースの操作を管理します.
    // mongodb
    package main
    
    import (
        "encoding/json"
        "log"
        "net/http"
    
        "github.com/gorilla/mux"
        "gopkg.in/mgo.v2"
        "gopkg.in/mgo.v2/bson"
    )
    
    var session *mgo.Session
    
    type Category struct {
        Id          bson.ObjectId `bson:"_id,omitempty"`
        Name        string
        Description string
        //Tasks       []Task
    }
    
    type DataStore struct {
        session *mgo.Session
    }
    
    /*
    type Task struct {
        Description string
        Due         time.Time
    }
    */
    
    //      collection
    func (d *DataStore) C(name string) *mgo.Collection {
        return d.session.DB("taskdb").C(name)
    }
    
    //   HTTP      DataStore  
    func NewDataStore() *DataStore {
        ds := &DataStore{
            session: session.Copy(),
        }
        return ds
    }
    
    func (d *DataStore) Close() {
        d.session.Close()
    }
    
    //      
    func PostCategory(w http.ResponseWriter, r *http.Request) {
        var category Category
    
        err := json.NewDecoder(r.Body).Decode(&category)
        if err != nil {
            panic(err)
        }
    
        ds := NewDataStore()
        defer ds.Close()
    
        c := ds.C("categories")
        err = c.Insert(&category)
    
        if err != nil {
            panic(err)
        }
        w.WriteHeader(http.StatusCreated)
    
    }
    
    func GetCategories(w http.ResponseWriter, r *http.Request) {
        var categories []Category
    
        ds := NewDataStore()
    
        defer ds.Close()
    
        c := ds.C("categories")
        iter := c.Find(nil).Iter()
    
        result := Category{}
    
        for iter.Next(&result) {
            categories = append(categories, result)
        }
        w.Header().Set("Content-Type", "application/json")
        j, err := json.Marshal(categories)
        if err != nil {
            panic(err)
        }
        w.WriteHeader(http.StatusOK)
        w.Write(j)
    }
    
    func main() {
        var err error
        session, err = mgo.Dial("localhost")
        if err != nil {
            panic(err)
        }
    
        r := mux.NewRouter()
        r.HandleFunc("/api/categories", GetCategories).Methods("GET")
        r.HandleFunc("/api/categories", PostCategory).Methods("POST")
    
        server := &http.Server{
            Addr:    ":9090",
            Handler: r,
        }
    
        log.Println("Listening...")
        server.ListenAndServe()
    }
    
    

    DataStoreの構造体を定義し、mgoを管理する.Session、更に2つの方法があります:CloseとC、Closeの方法は主にSessionオブジェクトがCloseの方法を呼び出して、資源の解放を行います.defer関数は、HTTPリクエストのライフサイクル終了時に呼び出す.
    NewDataStoreメソッドは、新しいDataStoreオブジェクトを作成し、Copy関数でDial関数のSessionオブジェクトを取得します.各ルーティングのhandlerについて、新しいセッションオブジェクトはDataStoreタイプによって使用する.簡単に言えば、グローバルなSessionオブジェクトを使用する方法はよくないので、HTTPリクエストの宣言周期でCopy 1つのSessionオブジェクトを使用する方法をお勧めします.この方法では複数のセッションオブジェクトが存在する.