mgoの基本的な操作まとめ

# 概要
Go言語のMongoDB Driverであるmgoを使ったコレクション、ドキュメントの基本的な操作方法をまとめました。またクエリの書き方についてmongo shellとの対比を行いました。

この記事の内容は下記のバージョンで動作確認を行いました。

* Windows7 (64bit)
* [mgo - Rich MongoDB driver for Go] (https://labix.org/mgo) v2
* [The Go Programming Language] (http://golang.org/) 1.4.2
* [MongoDB] (https://www.mongodb.org/) 3.0.2

## mgoの準備

### インストール

```go
> go get gopkg.in/mgo.v2
```

### 参考サイト

この記事の作成に関して下記のサイトを参考にしました。

mgo GoDoc

* [mgo - GoDoc] (http://godoc.org/labix.org/v2/mgo)
* [bson - GoDoc] (http://godoc.org/gopkg.in/mgo.v2/bson)

MongoDB manual

* [MongoDB manual - user privileges](http://docs.mongodb.org/manual/reference/user-privileges/)
* [MongoDB manual - built in roles](http://docs.mongodb.org/manual/reference/built-in-roles/)

MongoDB blog

* [MongoDB Blog - Running MongoDB Queries Concurrently With Go] (http://blog.mongodb.org/post/80579086742/running-mongodb-queries-concurrently-with-go)

## サンプルデータの準備

この記事で説明するサンプルコードの動作確認用に、下記の環境でサンプルデータを作成します。

### MongoDBの環境

* シングルノード
* データベース: `sample`
* コレクション: `columbo`

**コレクションの構造**

サンプルデータとして海外テレビドラマの情報を持つコレクションを扱います。コレクションの構造は下記のようになっています。

|field              |data type  |description  |
|:------------------|:----------|:------------|
|title              |string     |原題         |
|original_air_date  |string     |放送日       |
|runtime            |integer    |放送時間(分)  |
|guest_staring      |string     |ゲスト出演    |
|guest_staring_role |string     |ゲスト役柄    |
|directed_by        |string     |監督          |
|written_by         |array      |脚本          |
|teleplay           |array      |テレビ脚本    |
|season             |integer    |シーズン      |
|no_in_season       |integer    |シーズン回    |
|no_in_series       |integer    |放送回        |
|japanese_title     |String     |邦題         |
|japanese_air_date  |Date       |日本放送日    |

### サンプルデータの作成

mongo shellより下記のコマンドを実行してサンプルデータを作成します。
（長いので一部抜粋です、全文は付録Aに記載しています。）

```js:mongo_shell
> db.columbo.drop()
false

> db.columbo.insert([
{title:"Prescription: Murder",                original_air_date:"February 20, 1968",   runtime:98, guest_staring:"Gene Barry",        guest_staring_role:"Dr. Ray Fleming (Gene Barry), a psychiatrist",  directed_by:"Richard Irving",       written_by:["Richard Levinson & William Link"],                  teleplay:[""],                              season:0, no_in_season:1, no_in_series:1,  japanese_title:"殺人処方箋",                     japanese_air_date:ISODate("1972-08-27T00:00:00+09:00")},

～省略～

{title:"The Conspirators",                    original_air_date:"May 13, 1978",        runtime:98, guest_staring:"Clive Revill",      guest_staring_role:"Famous Irish poet and author Joe Devlin",      directed_by:"Leo Penn",             written_by:["Howard Berk"],                                      teleplay:[""],                              season:7, no_in_season:5, no_in_series:45, japanese_title:"策謀の結末",                      japanese_air_date:ISODate("1979-01-03T00:00:00+09:00"), based_on_an_idea_by: "Pat Robison"}
])
WriteResult({
    "writeErrors" : [ ],
    "writeConcernErrors" : [ ],
    "nInserted" : 45,
    "nUpserted" : 0,
    "nMatched" : 0,
    "nModified" : 0,
    "nRemoved" : 0,
    "upserted" : [ ]

> db.columbo.find().count()
45
```

## サンプルコード

### mgoパッケージ

mgoパッケージ、bsonパッケージをインポートします。

```go:go
import (
  "gopkg.in/mgo.v2"
  "gopkg.in/mgo.v2/bson"
)
```

### MongoDBへの接続と切断

MongoDBへ接続するには`Dial()`、`DialWithTimeout()`、`DialWithInfo()`などを使用します。

#### Dialを使用して接続します

urlで指定するMongoDBサーバーに接続します。`Dial()`が成功したときに返すSessionを通してMongoDBの操作を行います。
Sessionは不要になったらリソースを開放するために`Close()`を呼ぶ必要があります。閉じたSessionを使用するとエラーが発生します。
`Dial()`は`DialWithTimeout()`のラッパーメソッドです。タイムアウトは1分で設定されます。

```go:go
session, err := mgo.Dial("localhost:27017")
if err != nil {
  panic(err)
}
defer session.Close()

db := session.DB("sample")
```

レプリカセットを構成している場合、urlにはそのメンバーをカンマ区切りで指定します。

```text:example
mgo.Dial("localhost:30001,localhost:30002,localhost:30003")
```

urlのフォーマットは次の通りです。

```text
[mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
```

##### DialWithTimeout

タイムアウトする時間を任意の値で設定したい場合は`DialWithTimeout()`を使用します。timeoutに0を指定すると接続できるまで無期限に待機します。
`DialWithTimeout()`は`DialWithInfo()`のラッパーメソッドです。

この例では20秒でタイムアウトするように指定しています。

```go:go
session, err := mgo.DialWithTimeout("localhost:27017", 20*time.Second)
if err != nil {
  panic(err)
}
defer session.Close()

db := session.DB("sample")
```

##### DialWithInfo

`DialWithInfo()`は`DialInfo`に設定した情報を使用して接続を行います。ユーザー認証が必要な場合はUsername,Password,Sourceなどに認証情報を設定します。
この例では`session.DB()`に空のデータベース名を指定していますが、`DialInfo`で指定したデータベース名が使用されます。

```go:go
mongoInfo := &mgo.DialInfo{
  Addrs:    []string{"localhost:27017"},
  Timeout:  20 * time.Second,
  Database: "sample",
  Username: "peter",
  Password: "fark",
  Source: "sample",
}

session, err := mgo.DialWithInfo(mongoInfo)
if err != nil {
  panic(err)
}
defer session.Close()

// Databaseを指定していませんがDialInfoで指定した"sample"にアクセスします
db := session.DB("")
```

> GoDoc
>
> |name                                                               |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Dial](http://godoc.org/labix.org/v2/mgo#Dial)                       |`func Dial(url string) (*Session, error)`|
|[DialWithTimeout](http://godoc.org/labix.org/v2/mgo#DialWithTimeout) |`func DialWithTimeout(url string, timeout time.Duration) (*Session, error)`|
|[DialWithInfo](http://godoc.org/labix.org/v2/mgo#DialWithInfo)       |`func DialWithInfo(info *DialInfo) (*Session, error)`|
|[DialInfo](http://godoc.org/labix.org/v2/mgo#DialInfo)               |`type DialInfo struct` |


#### Sessionについて

`Dial()`で取得したSessionを`New()`,`Copy()`,`Clone()`で複製して、新しいSessionを作成することができます。

##### New()

オリジナルのセッションと同じパラメータ（一貫性(consistency)、バッチサイズ(batch size)、プリフェッチサイズ(prefetching)、セーフティーモード(safety mode)を含む）で新しいセッションを作成します。
ただし認証情報(Credential)はコピーしません。またオリジナルのセッションとは別に新しいソケットを作成します。

> 
> ```go:source
func (s *Session) New() *Session {
  s.m.Lock()
  scopy := copySession(s, false)
  s.m.Unlock()
  scopy.Refresh()
  return scopy
}
```

##### Copy()

オリジナルのセッションから認証情報(Credential)もコピーする以外は`New()`と同じ動作をします。

> 
> ```go:source
func (s *Session) Copy() *Session {
  s.m.Lock()
  scopy := copySession(s, true)
  s.m.Unlock()
  scopy.Refresh()
  return scopy
}
```

##### Clone()

`Copy()`と同じ動作をしますが、オリジナルのセッションと同じソケットを使用します。

> 
> ```go:source
func (s *Session) Clone() *Session {
  s.m.Lock()
  scopy := copySession(s, true)
  s.m.Unlock()
  return scopy
}
```

**各メソッドの差異について**

|method |Session parameter  |Credential           |Socket                      |
|:------|:-----------------:|:-------------------:|:--------------------------:|
|New    |コピーする          |クリアする            |新しいソケットを使う          |
|Copy   |コピーする          |コピーする            |新しいソケットを使う          |
|Clone  |コピーする          |コピーする            |オリジナルと同じソケットを使う |

##### 認証情報のコピーについて

MongoDBサーバーのドキュメントを操作するのにユーザー認証が必要な場合、`session.Login()`か`mgo.DialWithInfo()`を使用して認証を行う必要がありますが、この2つには下記の違いがあります。

**session.Login()を使用する場合**

`Dial()`時に認証は行わず`session.Login()`ではじめて認証を行います。このSessionを`New()`で複製しても認証情報はコピーされません。つまり新しいSessionでも`session.Login()`で認証を行う必要があります。

```go:go
masterSession, err := mgo.Dial("localhost:27017")
if err != nil {
  panic(err)
}
credential := &mgo.Credential{Username: "peter", Password: "fark", Source: "sample"}
if err := masterSession.Login(credential); err != nil {
  panic(err)
}

newSession := masterSession.New()
cl := newSession.DB("sample").C("columbo")
m := bson.M{}
err = ncl.Find(bson.M{"no_in_series":2}).One(&m)
if err != nil {
  fmt.Printf("Find error:%+v \n", err)
  // ⇒ Find error:not authorized for query on sample.test
} else {
  fmt.Printf("Fine success:%+v \n", m)
}
```

`Copy()`はオリジナルのセッションの認証情報もコピーしているので`session.Login()`をしなくても、そのまま使用することができます。

```go:go
copySession := masterSession.Copy()
cl := copySession.DB("sample").C("columbo")
err = cl.Find(bson.M{"no_in_series": 3}).One(&m)
if err != nil {
  fmt.Printf("Find error:%+v \n", err)
} else {
  fmt.Printf("Fine success:%+v \n", m)
  // ⇒ Fine success:map[title:Murder by the Book guest_staring_role:Ken Franklin is one half of a mystery writing team original_air_date:September 15, 1971 japanese_air_date:1972-11-26 00:00:00 +0900 JST _id:ObjectIdHex("557229340aa26682fd8d6408") runtime:73 directed_by:Steven Spielberg teleplay:[] japanese_title:構想の死角 guest_staring:Jack Cassidy written_by:[Steven Bochco] season:1 no_in_season:1 no_in_series:3]
}
```

**mgo.DialWithInfo()を使用する場合**

`mgo.DailWithInfo()`時に認証を行います。このSessionを`New()`で複製すると認証情報はコピーされます。つまり新しいSessionですぐにMongoDBのドキュメントを操作することができます。

```go:go
mongoInfo := &mgo.DialInfo{
  Addrs:    []string{"localhost:27017"},
  Timeout:  60 * time.Second,
  Database: "sample",
  Username: "peter",
  Password: "fark",
  Source:   "sample",
}
masterSession, err := mgo.DialWithInfo(mongoInfo)
if err != nil {
  panic(err)
}

cl := masterSession.DB("sample").C("columbo")
err = cl.Find(bson.M{"no_in_series": 1}).One(&m)
if err != nil {
  fmt.Printf("Find error:%+v \n", err)
} else {
  fmt.Printf("Fine success:%+v \n", m)
  // ⇒ Fine success:map[guest_staring_role:Dr. Ray Fleming (Gene Barry), a psychiatrist directed_by:Richard Irving _id:ObjectIdHex("557229340aa26682fd8d6406") runtime:98 season:0 no_in_season:1 no_in_series:1 japanese_air_date:1972-08-27 00:00:00 +0900 JST original_air_date:February 20, 1968 written_by:[Richard Levinson & William Link] japanese_title:殺人処方箋 title:Prescription: Murder teleplay:[] guest_staring:Gene Barry]
}

newSession := masterSession.New()
cl = newSession.DB("sample").C("columbo")
err = ncl.Find(bson.M{"no_in_series": 2}).One(&m)
if err != nil {
  fmt.Printf("Find error:%+v \n", err)
} else {
  fmt.Printf("Fine success:%+v \n", m)
  // ⇒ Fine success:map[title:Ransom for a Dead Man teleplay:[Dean Hargrove] japanese_title:死者の身代金 guest_staring:Lee Grant directed_by:Richard Irving _id:ObjectIdHex("557229340aa26682fd8d6407") runtime:98 guest_staring_role:Leslie Williams, a brilliant lawyer and pilot no_in_season:2 no_in_series:2 japanese_air_date:1973-04-22 00:00:00 +0900 JST original_air_date:March 1, 1971 written_by:[Richard Levinson & William Link] season:0]
}
```

> GoDoc
>
> |name                                                               |definition            |
|:--------------------------------------------------------------------|:---------------------|
|[Credential](http://godoc.org/gopkg.in/mgo.v2#Credential)            |`type Credential struct`|

#### SessionからFind().All()までの関連図(概略)

```go:go
err := session.DB("sample").C("columbo").Find(bson.M{}).All(&result)
```

```text
         +-[ DialInfo ]-----------------+
         |                              |
 +-------| Addrs          []string      |(Cluster)
 |       | Timeout        time.Duration |
 |       | Database       string        |
 |       | ReplicaSetName string        |(Cluster)
 |       | Source         string        |(Credential)
 |       | Mechanism      string        |(Credential)
 |       | Username       string        |(Credential)
 |       | Password       string        |(Credential)
 |       | PoolLimit      int           |
 |       +------------------------------+
 |       +-[ Credential ]---------------+
 |       |                              |
 |  +----| Username      string         |
 |  |    | Password      string         |
 |  |    | Source        string         |
 |  |    | Service       string         |
 |  |    | ServiceHost   string         |
 |  |    | Mechanism     string         |
 |  |    +------------------------------+
 |  |
 |  |    +-[ Session ]------------------+         +-[ Database ]-----+        +-[ Collection ]-----+
 |  |    |                              |         |                  |        |                    |
Dial()==>| cluster_     *mongoCluster   |==DB()==>| Session *Session |==C()==>| Database *Database |==Find()
         | slaveSocket  *mongoSocket    |         | Name     string  |        | Name      string   |
         | masterSocket *mongoSocket    |         |                  |        | FullName  string   |
         | slaveOk       bool           |         +------------------+        |                    |
         | consistency   mode           |                                     +--------------------+
         | queryConfig   query          |-------------+
         | safeOp       *queryOp        |             |
         | syncTimeout   time.Duration  |             |
         | sockTimeout   time.Duration  |             |
         | defaultdb     string         |             |
         | dialCred     *Credential     |             |
         | creds        []Credential    |         +- [query ]--------+
         | poolLimit     int            |         |                  |
         |                              |         | op       queryOp |
         +------------------------------+         | prefetch float64 |
                                                  | limit    int32   |
                                                  +------------------+

                                                            +-[ Iter ]---------------------+
                                                            |                              |
                                                            | gotReply       sync.Cond     |
                                                            | session        *Session      |
                                                            | server         *mongoServer  |
                                                            | docData        queue         |
                                                            | err            error         |
                                                            | op             getMoreOp     |
                                                            | prefetch       float64       |
                                                            | limit          int32         |
         +-[ Query ]--------------------+                   | docsToReceive  int           |
         |                              |                   | docsBeforeMore int           |
Find()==>| session *Session             |==All()==>Iter()==>| timeout        time.Duration |
         | query                        |                   | timedout       bool          |
         +------------------------------+                   +------------------------------+
```

> GoDoc
>
> |name                                                               |definition            |
|:--------------------------------------------------------------------|:---------------------|
|[Session](http://godoc.org/gopkg.in/mgo.v2#Session)                  |`type Session struct`                        |
|[Session.DB](http://godoc.org/labix.org/v2/mgo#Session.DB)           |`func (s *Session) DB(name string) *Database`|
|[Session.New](http://godoc.org/gopkg.in/mgo.v2#Session.New)          |`func (s *Session) New() *Session`           |
|[Session.Copy](http://godoc.org/gopkg.in/mgo.v2#Session.Copy)        |`func (s *Session) Copy() *Session`          |
|[Session.Clone](http://godoc.org/gopkg.in/mgo.v2#Session.Clone)      |`func (s *Session) Clone() *Session`         |
|[Session.Close](http://godoc.org/gopkg.in/mgo.v2#Session.Close)      |`func (s *Session) Close()`                  |

#### SetMode()

セッションの一貫性モードを変更します。MongoDBがレプリケーション構成の場合に意味を持ちます。

```go:go
session.SetMode(mgo.Monotonic, true)
```

**consistency**

|value           |description |
|:---------------|:-----------|
|mgo.Strong      |もっとも強い一貫性モードです。データの読み取り、書き込みはプリマリーノードに行います。デフォルトです。|
|mgo.Monotonic   |読み取りはセカンダリーノードで行いますが、書き込みが発生すると以降はプライマリーノードに対して読み取り、書き込みを行います。|
|mgo.Eventual    |結果整合性と呼ばれるモードです。読み取りはセカンダリーノードで行います。書き込みはプライマリーノードに行います。|

**refresh**

refreshにtrueを指定するとセッションのソケットをリリースして新しいソケットを作成します。
consistencyとの組み合わせにより一貫性モードの再設定が行われます。

例) consistencyを`mgo.Strong`でSessionを作成し、クエリを発行したあとで下記のパターンへ変えた場合。
（masterSocket,slaveSocket欄の`0x...`はsocketオブジェクトへのポインタがあることを意味します。）

|pattern                           |slaveOk|masterSocket|slaveSocket|description               |
|:---------------------------------|:------|:-----------|:----------|:-------------------------|
|`SetMode(mgo.Monotonic, true)`    |true   | nil        | 0x...     |slaveSocketを使用して接続、セカンダリーへ接続可   |
|`SetMode(mgo.Monotonic, false)`   |false  | 0x...      | nil       |masterSocketを使用して接続、セカンダリーへ接続不可 |

例) consistencyを`mgo.Monotonic`でSessionを作成し、クエリを発行したあとで下記のパターンへ変えた場合。

|pattern                           |slaveOk|masterSocket|slaveSocket|description               |
|:---------------------------------|:------|:-----------|:----------|:-------------------------|
|`SetMode(mgo.Strong, true)`       |false  | 0x...      | nil       |masterSocketを使用して接続、セカンダリーへ接続不可 |
|`SetMode(mgo.Strong, false)`      |false  | 0x...      | 0x...     |masterSocketを使用して接続、slaveSocketはそのまま、セカンダリーへ接続不可|

>
> ```go:source
func (s *Session) SetMode(consistency mode, refresh bool) {
  s.m.Lock()
  debugf("Session %p: setting mode %d with refresh=%v (master=%p, slave=%p)", s, consistency, refresh, s.masterSocket, s.slaveSocket)
  s.consistency = consistency
  if refresh {
    s.slaveOk = s.consistency != Strong
    s.unsetSocket()
  } else if s.consistency == Strong {
    s.slaveOk = false
  } else if s.masterSocket == nil {
    s.slaveOk = true
  }
  s.m.Unlock()
}
```

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Session.SetMode](http://godoc.org/labix.org/v2/mgo#Session.SetMode) |`func (s *Session) SetMode(consistency mode, refresh bool)`|
|[Session.Mode](http://godoc.org/labix.org/v2/mgo#Session.Mode)|`func (s *Session) Mode() mode`|
|[Session.Refresh](http://godoc.org/labix.org/v2/mgo#Session.Refresh) |`func (s *Session) Refresh()`|

#### SetSafe()

セッションのセーフティーモードを変更します。

**Unacknowledged**
完全にエラーの検証を無効にします。
更新処理の成否を確認しませんので高速に動作します。

```go:go
session.SetSafe(nil)
```

```go:go
session.SetSafe(&mgo.Safe{W: 0})
```

**Acknowledged**
デフォルトのモードです。
更新処理のエラーの検証を行います。このためgetLastErrorコマンドが実行されます。

```go:go
session.SetSafe(&mgo.Safe{})
```

```go:go
session.SetSafe(&mgo.Safe{W: 1})
```

**Journaled**
データのディスクへの書き込みを確認します。

```go:go
session.SetSafe(&mgo.Safe{W: 1, J: true})
```

**Replica Acknowledged**
レプリケーションのメンバーの過半数以上に書き込みされることを保証します。

```go:go
session.SetSafe(&mgo.Safe{WMode: "majority"})
```

**Safe**

書き込み保証オプションを下記の通り指定することができます。

|option        |description                                          |
|:-------------|:----------------------------------------------------|
|safe.W        |Min # of servers to ack before success               |
|safe.WMode    |Write mode for MongoDB 2.0+ (e.g. "majority")        |
|safe.WTimeout |Milliseconds to wait for W before timing out         |
|safe.FSync    |Should servers sync to disk before returning success |
|safe.J        |Wait for next group commit if journaling; no effect otherwise |

> GoDoc
>
>|name                                                                |definition         |
|:--------------------------------------------------------------------|:-------------|
|[Session.SetSafe](http://godoc.org/labix.org/v2/mgo#Session.SetSafe) |`func (s *Session) SetSafe(safe *Safe)`|
|[Session.Safe](http://godoc.org/labix.org/v2/mgo#Session.Safe)       |`func (s *Session) Safe() (safe *Safe)`|
|[Safe](http://godoc.org/labix.org/v2/mgo#Safe)                       |`type Safe struct`|

#### SetDebug()

デバッグモードの設定を行います。

Loggerへデバッグログを出力します。
この例では標準出力へデバッグログを出力します。

```go:go
logger := log.New(os.Stdout, "MGO: ", log.Lshortfile)
mgo.SetDebug(true)
mgo.SetLogger(logger)
```

>  GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[SetDebug](http://godoc.org/labix.org/v2/mgo#SetDebug)               |`func SetDebug(debug bool)`|
|[SetLogger](http://godoc.org/labix.org/v2/mgo#SetLogger)             |`func SetLogger(logger log_Logger)`|


### データベースの操作

#### コレクションの取得

**コレクションの情報を取得します**

```js:mongo_shell
> use sample
switched to db sample

> db.getCollectionNames()
[ "columbo", "system.indexes" ]
```

```go:go
db := session.DB("sample")

names, _ := db.CollectionNames()
for _, v := range names {
  fmt.Printf("collection name:%s\n", v)
  // ⇒ collection name:columbo
  // ⇒ collection name:system.indexes
}

cl := db.C("columbo")

fmt.Printf("Name:%s, FullName:%s\n", cl.Name, cl.FullName)
// ⇒ Name:columbo, FullName:sample.columbo
```

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Database](http://godoc.org/labix.org/v2/mgo#Database)               |`type Database struct`|
|[Database.C](http://godoc.org/labix.org/v2/mgo#Database.C)           |`func (db *Database) C(name string) *Collection` |
|[Database.CollectionNames](http://godoc.org/labix.org/v2/mgo#Database.CollectionNames)|`func (db *Database) CollectionNames() (names []string, err error)`|
|[Collection](http://godoc.org/labix.org/v2/mgo#Collection)           |`type Collection struct`|

**キャップド コレクションの作成**

この記事で使用する`columbo`コレクションは通常のコレクションとして作成しますので特別な操作は不要ですが、キャップドコレクションは`createCollection()`を使用して明示的に作成する必要があります。

```js:mongo_shell
> db.createCollection("columbo",{capped:true, size:1073741824, max:1000000})
{ "ok" : 1 }
```

```go:go
clInfo := &mgo.CollectionInfo{
  Capped:   true,
  MaxBytes: 1073741824,
  MaxDocs:  1000000,
}
err := cl.Create(clInfo)
if err != nil {
  fmt.Printf("%+v \n", err)
}
```

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Collection.Create](http://godoc.org/labix.org/v2/mgo#Collection.Create) |`func (c *Collection) Create(info *CollectionInfo) error`|
|[CollectionInfo](http://godoc.org/labix.org/v2/mgo#CollectionInfo)   |`type CollectionInfo struct`|


**ユニークインデックスの作成**

例) 放送回(no_in_series)にユニークインデックスを作成します。

```js:mongo_shell
> db.columbo.createIndex({no_in_series:1}, {unique:true, name:"columbo_uni01"})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
```

mgoではインデックス名を指定することはできないようです。

```go:go
index := mgo.Index{
  Key:    []string{"no_in_series"},
  Unique: true,
}
err := cl.EnsureIndex(index)
if err != nil {
  fmt.Println(err)
}
```

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Index](http://godoc.org/labix.org/v2/mgo#Index)                     |`type Index struct`|
|[EnsureIndex](http://godoc.org/labix.org/v2/mgo#Collection.EnsureIndex)|`func (c *Collection) EnsureIndex(index Index) error`|


#### ユーザーの操作

**ユーザーの作成と削除**

```js:mongo_shell
> db.createUser({user:"peter", pwd:"fark", roles:["readWrite","dbAdmin"]},{w:"majority", wtimeout:3000})
Successfully added user: { "user" : "peter", "roles" : [ "readWrite", "dbAdmin" ] }

> db.auth("peter","fark")
1

> db.logout()
{ "ok" : 1 }

> db.dropUser("peter")
true
```

```go:go
user := &mgo.User{
  Username: "peter",
  Password: "fark",
  Roles:    []mgo.Role{mgo.RoleReadWrite, mgo.RoleDBAdmin},
}

err = db.UpsertUser(user)
if err != nil {
  fmt.Printf("UpsertUser : %s\n", err)
}

err = db.Login("peter", "fark")
if err != nil {
  fmt.Printf("Login : %s\n", err)
}

db.Logout()

err := db.RemoveUser("peter")
if err != nil {
  fmt.Printf("RemoveUser : %s\n", err)
}
```

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Database.RemoveUser](http://godoc.org/labix.org/v2/mgo#Database.RemoveUser)|`func (db *Database) RemoveUser(user string) error`|
|[Database.UpsertUser](http://godoc.org/labix.org/v2/mgo#Database.UpsertUser)|`func (db *Database) UpsertUser(user *User) error`|
|[User](http://godoc.org/labix.org/v2/mgo#User)                       |`type User struct`|
|[Role](http://godoc.org/labix.org/v2/mgo#Role)                       |`type Role string`|
|[Database.Login](http://godoc.org/labix.org/v2/mgo#Database.Login)   |`func (db *Database) Login(user, pass string) error`|
|[Database.Logout](http://godoc.org/labix.org/v2/mgo#Database.Logout) |`func (db *Database) Logout()`|

### コレクションの操作

`columbo`コレクションをmgoから扱うための構造体を下記のように定義しました。

```go:go
type Columbo struct {
  ID               bson.ObjectId `bson:"_id,omitempty"`
  Title            string        `bson:"title"`
  OriginalAirDate  string        `bson:"original_air_date,omitempty"`
  Runtime          int           `bson:"runtime,omitempty"`
  GuestStaring     string        `bson:"guest_staring"`
  GuestStaringRole string        `bson:"guest_staring_role"`
  DirectedBy       string        `bson:"directed_by"`
  WrittenBy        []string      `bson:"written_by"`
  Teleplay         []string      `bson:"teleplay,omitempty"`
  Season           int           `bson:"season"`
  NoInSeason       int           `bson:"no_in_season"`
  NoInSeries       int           `bson:"no_in_series"`
  JapaneseTitle    string        `bson:"japanese_title"`
  JapaneseAirDate  time.Time     `bson:"japanese_air_date"`
}
```

#### 検索 (Find, FindId)

**条件を指定して検索します**

例) 検索条件にシーズン5のエピソードを指定して検索します。

```js:mongo_shell
> db.columbo.find(
  {season:5},
  {_id:0, title:1, runtime:1, guest_staring:1, season:1, no_in_season:1 no_in_series:1}
)
```

```go:go
result := []Columbo{}
err := cl.Find(bson.M{"season": 5}).Select(bson.M{"_id": 0, "title": 1, "runtime": 1, "guest_staring": 1, "season": 1, "no_in_season": 1, "no_in_series": 1}).All(&result)
if err != nil {
  fmt.Println(err)
}
for _, v := range result {
  fmt.Printf("%s %d %s %d %d %d\n", v.Title, v.Runtiem, v.GuestStaring, v.Season, v.NoInSeason, v.NoInSeries)
  // ⇒ Forgotten Lady, 85, Janet Leigh, 5, 1, 32
  // ⇒ A Case of Immunity, 73, Héctor Elizondo, 5, 2, 33
  // ⇒ Identity Crisis, 98, Patrick McGoohan, 5, 3, 34
  // ⇒ A Matter of Honor, 73, Ricardo Montalban, 5, 4, 35
  // ⇒ Now You See Him..., 85, Jack Cassidy, 5, 5, 36
  // ⇒ Last Salute to the Commodore, 98, Robert Vaughn, 5, 6, 37
}
```

`All()`は検索結果をすべてresultへ格納しようとしますので、検索するドキュメントの件数が多い場合はメモリーを枯渇させる危険性があります。場合によっては`All()`と`Limit`を併用する必要があるかもしれません。

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Collection.Find](http://godoc.org/labix.org/v2/mgo#Collection.Find) |`func (c *Collection) Find(query interface{}) *Query`|
|[Query.Select](http://godoc.org/labix.org/v2/mgo#Query.Select)       |`func (q *Query) Select(selector interface{}) *Query`|
|[Query.All](http://godoc.org/labix.org/v2/mgo#Query.All)             |`func (q *Query) All(result interface{}) error`|
|[Iter.All](http://godoc.org/labix.org/v2/mgo#Iter.All)               |`func (iter *Iter) All(result interface{}) error`|


**検索するドキュメントの件数を制限します**

例) 無条件に検索したドキュメントを10件スキップした後の5件を取得します。

```js:mongo_shell
> db.columbo.find().skip(10).limit(5)
```

```go:go
result := []Columbo{}
err := cl.Find(bson.M{}).Skip(10).Limit(5).All(&result)
if err != nil {
  fmt.Println(err)
}
for _, v := range result {
  fmt.Printf("%s, %d, %s, %d, %d, %d\n", v.Title, v.Runtiem, v.GuestStaring, v.Season, v.NoInSeason, v.NoInSeries)
  // ⇒ The Greenhouse Jungle, 73, Ray Milland, 2, 2, 11
  // ⇒ The Most Crucial Game, 73, Robert Culp, 2, 3, 12
  // ⇒ Dagger of the Mind, 98, Richard Basehart, 2, 4, 13
  // ⇒ Requiem for a Falling Star, 73, Anne Baxter, 2, 5, 14
  // ⇒ A Stitch in Crime, 73, Leonard Nimoy, 2, 6, 15
}
```

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Query.Limit](http://godoc.org/labix.org/v2/mgo#Query.Limit)         |`func (q *Query) Limit(n int) *Query`|
|[Query.Skip](http://godoc.org/labix.org/v2/mgo#Query.Skip)           |`func (q *Query) Skip(n int) *Query` |


**範囲を指定してドキュメントを検索します**

例) 放送回(no_in_series)が30回から39回までのエピソードを検索します。

```js:mongo_shell
> db.columbo.find(
  {$and:[ {no_in_series:{$gte:30}}, {no_in_series:{$lte:39}} ]},
  {_id:0, title:1, runtime:1, guest_staring:1, season:1, no_in_season:1, no_in_series:1}
)
```

```go:go
result := []Columbo{}
err := cl.Find(bson.M{"$and": []interface{}{
  bson.M{"no_in_series": bson.M{"$gte": 30}},
  bson.M{"no_in_series": bson.M{"$lte": 39}}}}).Select(bson.M{"_id": 0, "title": 1, "runtime": 1, "guest_staring": 1, "season": 1, "no_in_season": 1, "no_in_series": 1}).All(&result)
if err != nil {
  fmt.Println(err)
}
for _, v := range result {
  fmt.Printf("%s, %d, %s, %d, %d, %d\n", v.Title, v.Runtiem, v.GuestStaring, v.Season, v.NoInSeason, v.NoInSeries)
  // ⇒ Playback, 73, Oskar Werner, 4, 5, 30
  // ⇒ A Deadly State of Mind, 73, George Hamilton, 4, 6, 31
  // ⇒ Forgotten Lady, 85, Janet Leigh, 5, 1, 32
  // ⇒ A Case of Immunity, 73, Héctor Elizondo, 5, 2, 33
  // ⇒ Identity Crisis, 98, Patrick McGoohan, 5, 3, 34
  // ⇒ A Matter of Honor, 73, Ricardo Montalban, 5, 4, 35
  // ⇒ Now You See Him..., 85, Jack Cassidy, 5, 5, 36
  // ⇒ Last Salute to the Commodore, 98, Robert Vaughn, 5, 6, 37
  // ⇒ Fade in to Murder, 73, William Shatner, 6, 1, 38
  // ⇒ Old Fashioned Murder, 73, Joyce Van Patten, 6, 2, 39
}
```

**検索したドキュメントをソートします**

例) 放送時間(runtime)が98分のエピソードを検索し、放送回(no_in_series)が新しい順に並べ替えます。

```js:mongo_shell
> db.columbo.find(
  {runtime:{$eq:98}},
  {_id:0, title:1, original_air_date:1, runtime:1, guest_staring:1, season:1, no_in_season:1, no_in_series:1}
).sort({no_in_series:-1})
```

```go:go
result := []Columbo{}
err := cl.Find(bson.M{"runtime": bson.M{"$eq": 98}}).Select(bson.M{"_id": 0, "title": 1, "runtime": 1, "guest_staring": 1, "season": 1, "no_in_season": 1, "no_in_series": 1}).Sort("-no_in_series").All(&result)
if err != nil {
  fmt.Println(err)
}
for _, v := range result {
  fmt.Printf("%s, %d, %s, %d, %d, %d\n", v.Title, v.Runtiem, v.GuestStaring, v.Season, v.NoInSeason, v.NoInSeries)
  // ⇒ The Conspirators, 98, Clive Revill, 7, 5, 45
  // ⇒ Make Me a Perfect Murder, 98, Trish Van Devere, 7, 3, 43
  // ⇒ Last Salute to the Commodore, 98, Robert Vaughn, 5, 6, 37
  // ⇒ Identity Crisis, 98, Patrick McGoohan, 5, 3, 34
  // ⇒ Troubled Waters, 98, Robert Vaughn, 4, 4, 29
  // ⇒ By Dawn's Early Light, 98, Patrick McGoohan, 4, 3, 28
  // ⇒ Negative Reaction, 98, Dick Van Dyke, 4, 2, 27
  // ⇒ An Exercise in Fatality, 98, Robert Conrad, 4, 1, 26
  // ⇒ A Friend in Deed, 98, Richard Kiley, 3, 8, 25
  // ⇒ Swan Song, 98, Johnny Cash, 3, 7, 24
  // ⇒ Candidate for Crime, 98, Jackie Cooper, 3, 3, 20
  // ⇒ Any Old Port in a Storm, 98, Donald Pleasence, 3, 2, 19
  // ⇒ Dagger of the Mind, 98, Richard Basehart, 2, 4, 13
  // ⇒ Étude in Black, 98, John Cassavetes, 2, 1, 10
  // ⇒ Ransom for a Dead Man, 98, Lee Grant, 0, 2, 2
  // ⇒ Prescription: Murder, 98, Gene Barry, 0, 1, 1
}
```

デフォルトでは昇順、フィールド名の先頭に`-`を付けると降順にソートします。

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Query.Sort](http://godoc.org/labix.org/v2/mgo#Query.Sort)           |`func (q *Query) Sort(fields ...string) *Query`|

**正規表現で検索条件を指定します**

例) 放送年に関わらず3月に放送されたエピソードを検索します。

```js:mongo_shell
> db.columbo.find(
  {original_air_date:{$regex:/^March.*/}},
  {_id:0, title:1, original_air_date:1, runtime:1, guest_staring:1, season:1, no_in_season:1, no_in_series:1}
)
```

```go:go
result := []Columbo{}
err := cl.Find(bson.M{"original_air_date": bson.M{"$regex": bson.RegEx{Pattern: `^March.*`, Options:"m"}}}).Select(bson.M{"_id": 0, "title": 1, "runtime": 1, "guest_staring": 1, "season": 1, "no_in_season": 1, "no_in_series": 1, "original_air_date": 1}).Sort("-no_in_series").All(&result)
if err != nil {
  fmt.Println(err)
}
for _, v := range result {
  fmt.Printf("%s, %d, %s, %d, %d, %d, %s\n", v.Title, v.Runtiem, v.GuestStaring, v.Season, v.NoInSeason, v.NoInSeries, v.OriginalAirDate)
  // ⇒ Ransom for a Dead Man, 98, Lee Grant, 0, 2, 2, March 1, 1971
  // ⇒ The Most Dangerous Match, 73, Laurence Harvey, 2, 7, 16, March 4, 1973
  // ⇒ Double Shock, 73, Martin Landau, 2, 8, 17, March 25, 1973
  // ⇒ Swan Song, 98, Johnny Cash, 3, 7, 24, March 3, 1974
  // ⇒ Playback, 73, Oskar Werner, 4, 5, 30, March 2, 1975
}
```

**Options**

|option |description                       |
|:-----:|:---------------------------------|
|i      |case insensitive matching         |
|m      |multi-line matching               |
|x      |verbose mode                      |
|l      |\w, \W, and similar be locale-dependent |
|s      |dot-all mode                      |
|u      |\w, \W, and similar match unicode |

> GoDoc
>
>|name                                                                |definition          |
|:--------------------------------------------------------------------|:-------------------|
|[RegEx](http://godoc.org/gopkg.in/mgo.v2/bson#RegEx)                 |`type RegEx struct` |


**条件にあうドキュメントを1件検索します**

例) シーズン第1回目のエピソードを1件検索します。

```js:mongo_shell
> db.columbo.findOne(
  {no_in_season:1},
  {_id:0, title:1, original_air_date:1, runtime:1, guest_staring:1, season:1, no_in_season:1, no_in_series:1}
)
```

```go:go
columbo := &Columbo{}
err := cl.Find(bson.M{"no_in_season": bson.M{"$eq": 1}}).Select(bson.M{"_id": 0, "title": 1, "runtime": 1, "guest_staring": 1, "season": 1, "no_in_season": 1, "no_in_series": 1}).One(&columbo)
if err != nil {
  if v, ok := err.(*mgo.QueryError); ok {
    fmt.Printf("%+v \n", v)
  } else {
    fmt.Printf("%+v \n", err)
  }
}
fmt.Printf("%s, %d, %s, %d, %d, %d\n", columbo.Title, columbo.Runtiem, columbo.GuestStaring, columbo.Season, columbo.NoInSeason, columbo.NoInSeries)
// ⇒ Prescription: Murder, 98, Gene Barry, 0, 1, 1
```

検索条件にあうドキュメントが見つからなかった場合は`ErrNotFound`が返ります。
それ以外はerrはQueryError型になります。

例) 下記はSelectメソッドの記述が正しくなかった場合の出力結果になります。

```go:go
if err != nil {
  fmt.Printf("%+v \n", reflect.TypeOf(err))
  // ⇒ *mgo.QueryError
  if v, ok := err.(*mgo.QueryError); ok {
    fmt.Printf("%+v \n", v)
    // ⇒ Can't canonicalize query: BadValue Projection cannot have a mix of inclusion and exclusion.
  } else {
    fmt.Printf("%+v \n", err)
  }
}
```

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Query.One](http://godoc.org/labix.org/v2/mgo#Query.One)             |`func (q *Query) One(result interface{}) (err error)`|
|[QueryError](http://godoc.org/labix.org/v2/mgo#QueryError)           |`type QueryError struct`|


**ObjectIdを指定して検索します**

```js:mongo_shell
> db.columbo.find(
  {_id:ObjectId("556ce9b2f5c33ee8cd7ea852")},
  {_id:0, title:1, original_air_date:1, runtime:1, guest_staring:1, season:1, no_in_season:1, no_in_series:1}
)
```

```go:go
columbo := &Columbo{}
err := cl.FindId(bson.ObjectIdHex("556ce9b2f5c33ee8cd7ea852")).One(&columbo)
if err != nil {
  fmt.Println(err)
}
fmt.Printf("%s, %d, %s, %d, %d, %d\n", columbo.Title, columbo.Runtiem, columbo.GuestStaring, columbo.Season, columbo.NoInSeason, columbo.NoInSeries)
// ⇒ Candidate for Crime, 98, Jackie Cooper, 3, 3, 20
```

FindIdは以下のFindと同じ意味になります。

```go:go
err := cl.Find(bson.M{"_id": bson.ObjectIdHex("556ce9b2f5c33ee8cd7ea852")}).One(&columbo)
```

**検索結果をbson.M型に格納します**

特定の型を使用しない方法です。
検索するドキュメントのスキーマが不定の場合などで使用できます。

```go:go
result := bson.M{}
err := cl.Find(bson.M{"no_in_series": 10}).One(&m)
if err != nil {
   fmt.Printf("%+v \n", err)
} else {
  for key, value := range m {
    fmt.Printf("key:%s, value:%v \n", key, value)
    // ⇒ key:guest_staring, value:John Cassavetes
    // ⇒ key:directed_by, value:Nicholas Colasanto
    // ⇒ key:_id, value:ObjectIdHex("5570a16c15cc230577dd7f57")
    // ⇒ key:runtime, value:98
    // ⇒ key:guest_staring_role, value:Alex Benedict, The conductor of the Los Angeles Philharmonic Orchestra
    // ⇒ key:original_air_date, value:September 17, 1972
    // ⇒ key:written_by, value:[Richard Levinson & William Link]
    // ⇒ key:season, value:2
    // ⇒ key:no_in_season, value:1
    // ⇒ key:no_in_series, value:10
    // ⇒ key:japanese_air_date, value:1973-09-30 00:00:00 +0900 JST
    // ⇒ key:teleplay, value:[Steven Bochco]
    // ⇒ key:japanese_title, value:黒のエチュード
    // ⇒ key:title, value:Étude in Black
  }
}
```

**検索結果をbson.D型に格納します**

bson.Dでも同様のことが行えます。

```go:go
var d bson.D
err := cl.Find(bson.M{"no_in_series": 10}).One(&d)
if err != nil {
  fmt.Printf("%+v \n", err)
} else {
  for _, elem := range d {
    fmt.Printf("name:%s, value:%v \n", elem.Name, elem.Value)
    // ⇒ name:_id, value:ObjectIdHex("5570a3d815cc230577dd7f8c")
    // ⇒ name:japanese_air_date, value:1973-09-30 00:00:00 +0900 JST
    // ⇒ name:original_air_date, value:September 17, 1972
    // ⇒ name:guest_staring, value:John Cassavetes
    // ⇒ name:written_by, value:[Richard Levinson & William Link]
    // ⇒ name:season, value:2
    // ⇒ name:no_in_season, value:1
    // ⇒ name:no_in_series, value:10
    // ⇒ name:title, value:Étude in Black
    // ⇒ name:runtime, value:98
    // ⇒ name:guest_staring_role, value:Alex Benedict, The conductor of the Los Angeles Philharmonic Orchestra
    // ⇒ name:directed_by, value:Nicholas Colasanto
    // ⇒ name:teleplay, value:[Steven Bochco]
    // ⇒ name:japanese_title, value:黒のエチュード
  }
}
```

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Collection.FindId](http://godoc.org/labix.org/v2/mgo#Collection.FindId) |`func (c *Collection) FindId(id interface{}) *Query`|
|[ObjectIdHex](http://godoc.org/gopkg.in/mgo.v2/bson#ObjectIdHex)     |`func ObjectIdHex(s string) ObjectId`|


#### 追加 (Insert,Bulk)

**1件のドキュメントを追加します**

例) シーズン8の第1話を追加します。

```js:mongo_shell
> db.columbo.insert({title:"Columbo Goes to the Guillotine",   runtime:93, guest_staring:"Anthony Andrews", guest_staring_role:"Elliott Blake, A psychic", directed_by:"Leo Penn",      written_by:["William Read Woodfield"], teleplay:[""], season:8, no_in_season:1, no_in_series:46, japanese_title:"汚れた超能力", japanese_air_date:ISODate("1993-05-07T00:00:00+0900")})
WriteResult({ "nInserted" : 1 })
```

```go:go
lc, _ := time.LoadLocation("Asia/Tokyo")

columbo := Columbo{}
columbo.ID = bson.NewObjectId()
columbo.Title = "Columbo Goes to the Guillotine"
columbo.Runtime = 93
columbo.GuestStaring = "Anthony Andrews"
columbo.GuestStaringRole = "Elliott Blake, A psychic"
columbo.DirectedBy = "Leo Penn"
columbo.WrittenBy = []string{"William Read Woodfield"}
columbo.Teleplay = []string{""}
columbo.Season = 8
columbo.NoInSeason = 1
columbo.NoInSeries = 46
columbo.JapaneseTitle = "汚れた超能力"
columbo.JapaneseAirDate = time.Date(1993, 5, 7, 0, 0, 0, 0, lc)
err := cl.Insert(&columbo)
if err != nil {
  if mgo.IsDup(err) {
    fmt.Printf("Duplicate key error \n")
  }
  if v, ok := err.(*mgo.LastError); ok {
    fmt.Printf("Code:%d N:%d UpdatedExisting:%t WTimeout:%t Waited:%d \n", v.Code, v.N, v.UpdatedExisting, v.WTimeout, v.Waited)
  } else {
     fmt.Printf("%+v \n", err)
  }
}
```

errが返ってきた場合`mgo.IsDup()`で重複エラーか判定することができます。
また、セッションがセーフモードのときのerrはLastError型です。

> GoDoc
>
>|s                                                                    |v             |
|:--------------------------------------------------------------------|:-------------|
|[Collection.Insert](http://godoc.org/labix.org/v2/mgo#Collection.Insert) |`func (c *Collection) Insert(docs ...interface{}) error`|
|[IsDup](http://godoc.org/labix.org/v2/mgo#IsDup)                     |`func IsDup(err error) bool`|
|[LastError](http://godoc.org/labix.org/v2/mgo#LastError)             |`type LastError struct`|

**複数件のドキュメントをまとめて追加します**

例) シーズン8の残り3話をまとめて追加します。

```js:mongo_shell
> db.columbo.insert([
{title:"Murder, Smoke and Shadows",           runtime:95, guest_staring:"Fisher Stevens",  guest_staring_role:"Boy genius Hollywood director Alex Brady", directed_by:"James Frawley", written_by:["Richard Alan Simmons"],   teleplay:[""], season:8, no_in_season:2, no_in_series:47, japanese_title:"狂ったシナリオ", japanese_air_date:ISODate("1993-06-04T00:00:00+0900")},
{title:"Sex and the Married Detective",       runtime:94, guest_staring:"Lindsay Crouse",  guest_staring_role:"Sex therapist Dr. Joan Allenby", directed_by:"James Frawley", written_by:["Jerry Ludwig"],           teleplay:[""], season:8, no_in_season:3, no_in_series:48, japanese_title:"幻の娼婦", japanese_air_date:ISODate("1993-07-02T00:00:00+09:00")},
{title:"Grand deceptions",                    runtime:95, guest_staring:"Robert Foxworth", guest_staring_role:"Colonel Frank Brailie", directed_by:"Sam Wanamaker", written_by:["Sy Salkowitz"],           teleplay:[""], season:8, no_in_season:4, no_in_series:49, japanese_title:"迷子の兵隊", japanese_air_date:ISODate("1993-09-17T00:00:00+09:00")}
])
BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 3,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})
```

```go:go
columboSeason8 := []*Columbo{
&Columbo{ID: bson.NewObjectId(), Title: "Murder, Smoke and Shadows", Runtime: 95, GuestStaring: "Fisher Stevens", GuestStaringRole: "Boy genius Hollywood director Alex Brady", DirectedBy: "James Frawley", WrittenBy: []string{"Richard Alan Simmons"}, Teleplay: []string{""}, Season: 8, NoInSeason: 2, NoInSeries: 47, JapaneseTitle: "狂ったシナリオ", JapaneseAirDate: time.Date(1993, 6, 4, 0, 0, 0, 0, lc)},
&Columbo{ID: bson.NewObjectId(), Title: "Sex and the Married Detective", Runtime: 94, GuestStaring: "Lindsay Crouse", GuestStaringRole: "Sex therapist Dr. Joan Allenby", DirectedBy: "James Frawley", WrittenBy: []string{"Jerry Ludwig"}, Teleplay: []string{""}, Season: 8, NoInSeason: 3, NoInSeries: 48, JapaneseTitle: "幻の娼婦", JapaneseAirDate: time.Date(1993, 7, 2, 0, 0, 0, 0, lc)},
&Columbo{ID: bson.NewObjectId(), Title: "Grand deceptions", Runtime: 95, GuestStaring: "Robert Foxworth", GuestStaringRole: "Colonel Frank Brailie", DirectedBy: "Sam Wanamaker", WrittenBy: []string{"Sy Salkowitz"}, Teleplay: []string{""}, Season: 8, NoInSeason: 4, NoInSeries: 49, JapaneseTitle: "迷子の兵隊", JapaneseAirDate: time.Date(1993, 9, 17, 0, 0, 0, 0, lc)},
}

ca := make([]interface{}, len(columboSeason8))
for i, v := range columboSeason8 {
  ca[i] = v
}
err = cl.Insert(ca...)
if err != nil {
  fmt.Printf("%+v \n", err)
}
```

**Bulkインサートでドキュメントをまとめて追加します**

例) シーズン9の全6話をBulkインサートで追加します。

```js:mongo_shell
> var bulk = db.columbo.initializeOrderedBulkOp()
> bulk.insert({title:"Murder, a Self-Portrait",     original_air_date:"November 25, 1989", guest_staring:"Patrick Bauchau",  guest_staring_role:"Temperamental artist Max Barsini",        directed_by:"James Frawley",    written_by:["Robert Sherman"],         teleplay:[""], no_in_season:1, no_in_series:50, japanese_title:"殺意のキャンバス",     japanese_air_date:ISODate("1994-11-04T00:00:00+09:00")})
> bulk.insert({title:"Columbo Cries Wolf",          original_air_date:"January 20, 1990",  guest_staring:"Ian Buchanan",     guest_staring_role:"men's magazine publisher Sean Brantley",  directed_by:"Daryl Duke",       written_by:["William Read Woodfield"], teleplay:[""], no_in_season:2, no_in_series:51, japanese_title:"だまされたコロンボ",   japanese_air_date:ISODate("1994-06-17T00:00:00+09:00")})
> bulk.insert({title:"Agenda for Murder",           original_air_date:"February 10, 1990", guest_staring:"Patrick McGoohan", guest_staring_role:"Oscar Finch, A lawyer",                   directed_by:"Patrick McGoohan", written_by:["Jeffrey Bloom"],          teleplay:[""], no_in_season:3, no_in_series:52, japanese_title:"完全犯罪の誤算",       japanese_air_date:ISODate("1995-03-17T00:00:00+09:00")})
> bulk.insert({title:"Rest in Peace, Mrs. Columbo", original_air_date:"March 31, 1990",    guest_staring:"Helen Shaver",     guest_staring_role:"Vivian Dimitri, A real-estate executive", directed_by:"Vincent McEveety", written_by:["Peter S. Fischer"],       teleplay:[""], no_in_season:4, no_in_series:53, japanese_title:"かみさんよ、安らかに", japanese_air_date:ISODate("1995-04-14T00:00:00+09:00")})
> bulk.insert({title:"Uneasy Lies the Crown",       original_air_date:"April 28, 1990",    guest_staring:"James Read",       guest_staring_role:"Dentist Dr. Wesley Corman",               directed_by:"Alan J. Levi",     written_by:["Steven Bochco"],          teleplay:[""], no_in_season:5, no_in_series:54, japanese_title:"華麗なる罠",           japanese_air_date:ISODate("1994-12-02T00:00:00+09:00")})
> bulk.insert({title:"Murder in Malib",             original_air_date:"May 14, 1990",      guest_staring:"Andrew Stevens",   guest_staring_role:"Wayne Jennings, Actor",                   directed_by:"Walter Grauman",   written_by:["Jackson Gillis"],         teleplay:[""], no_in_season:6, no_in_series:55, japanese_title:"マリブビーチ殺人事件", japanese_air_date:ISODate("1994-10-14T00:00:00+09:00")})
bulk.execute()
BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 6,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})
```

```go:go
columboSeason9 := []*Columbo{
&Columbo{ID: bson.NewObjectId(), Title: "Murder, a Self-Portrait", OriginalAirDate: "November 25, 1989", Runtime: 0, GuestStaring: "Patrick Bauchau", GuestStaringRole: "Temperamental artist Max Barsini", DirectedBy: "James Frawley", WrittenBy: []string{"Robert Sherman"}, Teleplay: []string{""}, NoInSeason: 1, NoInSeries: 50, JapaneseTitle: "殺意のキャンバス", JapaneseAirDate: time.Date(1994, 11, 4, 0, 0, 0, 0, lc)},
&Columbo{ID: bson.NewObjectId(), Title: "Columbo Cries Wolf", OriginalAirDate: "January 20, 1990", Runtime: 0, GuestStaring: "Ian Buchanan", GuestStaringRole: "men's magazine publisher Sean Brantley", DirectedBy: "Daryl Duke", WrittenBy: []string{"William Read Woodfield"}, Teleplay: []string{""}, NoInSeason: 2, NoInSeries: 51, JapaneseTitle: "だまされたコロンボ", JapaneseAirDate: time.Date(1994, 6, 17, 0, 0, 0, 0, lc)},
&Columbo{ID: bson.NewObjectId(), Title: "Agenda for Murder", OriginalAirDate: "February 10, 1990", Runtime: 0, GuestStaring: "Patrick McGoohan", GuestStaringRole: "Oscar Finch, A lawyer", DirectedBy: "Patrick McGoohan", WrittenBy: []string{"Jeffrey Bloom"}, Teleplay: []string{""}, NoInSeason: 3, NoInSeries: 52, JapaneseTitle: "完全犯罪の誤算", JapaneseAirDate: time.Date(1995, 3, 17, 0, 0, 0, 0, lc)},
&Columbo{ID: bson.NewObjectId(), Title: "Rest in Peace, Mrs. Columbo", OriginalAirDate: "March 31, 1990", Runtime: 0, GuestStaring: "Helen Shaver", GuestStaringRole: "Vivian Dimitri, A real-estate executive", DirectedBy: "Vincent McEveety", WrittenBy: []string{"Peter S. Fischer"}, Teleplay: []string{""}, NoInSeason: 4, NoInSeries: 53, JapaneseTitle: "かみさんよ、安らかに", JapaneseAirDate: time.Date(1995, 04, 14, 0, 0, 0, 0, lc)},
&Columbo{ID: bson.NewObjectId(), Title: "Uneasy Lies the Crown", OriginalAirDate: "April 28, 1990", Runtime: 0, GuestStaring: "James Read", GuestStaringRole: "Dentist Dr. Wesley Corman", DirectedBy: "Alan J. Levi", WrittenBy: []string{"Steven Bochco"}, Teleplay: []string{""}, NoInSeason: 5, NoInSeries: 54, JapaneseTitle: "華麗なる罠", JapaneseAirDate: time.Date(1994, 12, 2, 0, 0, 0, 0, lc)},
&Columbo{ID: bson.NewObjectId(), Title: "Murder in Malib", OriginalAirDate: "May 14, 1990", Runtime: 0, GuestStaring: "Andrew Stevens", GuestStaringRole: "Wayne Jennings, Actor", DirectedBy: "Walter Grauman", WrittenBy: []string{"Jackson Gillis"}, Teleplay: []string{""}, NoInSeason: 6, NoInSeries: 55, JapaneseTitle: "マリブビーチ殺人事件", JapaneseAirDate: time.Date(1994, 10, 14, 0, 0, 0, 0, lc)},
}

bulk := cl.Bulk()
for _, v := range columboSeason9 {
  bulk.Insert(v)
}

var bulkRes *mgo.BulkResult
var err error
bulkRes, err = bulk.Run()
if err != nil {
  fmt.Printf("%+v \n", err)
}
if bulkRes != nil {
  fmt.Printf("bulkResult: %+v \n", bulkRes)
  // ⇒ bulkResult: &{private:false}
}
```

**bson.M型を使用してドキュメントを追加します**

特定の型を使用しない方法です。
マップのキーがそのままMongoDBのドキュメントのフィールド名になります。

```go:go
lc, _ := time.LoadLocation("Asia/Tokyo")

sdocs := []*bson.M{
&bson.M{"title": "Prescription: Murder", "original_air_date": "February 20, 1968", "runtime": 98, "guest_staring": "Gene Barry", "guest_staring_role": "Dr. Ray Fleming (Gene Barry), a psychiatrist", "directed_by": "Richard Irving", "written_by": []string{"Richard Levinson & William Link"}, "teleplay": []string{""}, "season": 0, "no_in_season": 1, "no_in_series": 1, "japanese_title": "殺人処方箋", "japanese_air_date": time.Date(1972, 8, 27, 0, 0, 0, 0, lc)},
&bson.M{"title": "Ransom for a Dead Man", "original_air_date": "March 1, 1971", "runtime": 98, "guest_staring": "Lee Grant", "guest_staring_role": "Leslie Williams, a brilliant lawyer and pilot", "directed_by": "Richard Irving", "written_by": []string{"Richard Levinson & William Link"}, "teleplay": []string{"Dean Hargrove"}, "season": 0, "no_in_season": 2, "no_in_series": 2, "japanese_title": "死者の身代金", "japanese_air_date": time.Date(1973, 4, 22, 0, 0, 0, 0, lc)},
&bson.M{"title": "Murder by the Book", "original_air_date": "September 15, 1971", "runtime": 73, "guest_staring": "Jack Cassidy", "guest_staring_role": "Ken Franklin is one half of a mystery writing team", "directed_by": "Steven Spielberg", "written_by": []string{"Steven Bochco"}, "teleplay": []string{""}, "season": 1, "no_in_season": 1, "no_in_series": 3, "japanese_title": "構想の死角", "japanese_air_date": time.Date(1972, 11, 26, 0, 0, 0, 0, lc)},
}
docs := make([]interface{}, len(sdocs))
for i, v := range sdocs {
  docs[i] = v
}
err := cl.Insert(docs...)
if err != nil {
  log.Prinf("%+v \n", err)
}
```

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Bulk](http://godoc.org/labix.org/v2/mgo#Bulk)                       |`type Bulk struct`|
|[Bulk.Insert](http://godoc.org/labix.org/v2/mgo#Bulk.Insert)         |`func (b *Bulk) Insert(docs ...interface{})`|
|[Bulk.Run](http://godoc.org/labix.org/v2/mgo#Bulk.Run)               |`func (b *Bulk) Run() (*BulkResult, error)`|
|[BulkResult](http://godoc.org/labix.org/v2/mgo#BulkResult)           |`type BulkResult struct`|


#### 更新 (Update, UpdateId)

**条件にあうドキュメントを1件更新します**

例) 指定するエピソードの放送日(original_air_date)を更新します。

```js:mongo_shell
> db.columbo.update({title:"Columbo Goes to the Guillotine"},{$set:{original_air_date:"February 6, 1989"}})
```

selectorの条件に一致するドキュメントが複数ある場合でも更新されるのはそのうちの1件だけです。

```go:go
selector := bson.M{"title": "Columbo Goes to the Guillotine"}
update := bson.M{"$set": bson.M{"original_air_date": "February 6, 1989"}}
err := cl.Update(selector, update)
if err != nil {
  if mgo.IsDup(err) {
    fmt.Printf("Duplicate key error \n")
  }
  if v, ok := err.(*mgo.LastError); ok {
    fmt.Printf("Code:%d N:%d UpdatedExisting:%t WTimeout:%t Waited:%d \n", v.Code, v.N, v.UpdatedExisting, v.WTimeout, v.Waited)
  } else {
    fmt.Printf("%+v \n", err)
  }
}
```

**範囲を指定して複数件を更新します**

例) 放送回(no_in_series)が50回から55回までをシーズン9として更新します。

```js:mongo_shell
> db.columbo.update({$and:[{no_in_series:{$gte:50}},{no_in_series:{$lte:55}}]},{$set:{season:9}},{multi:true})
WriteResult({ "nMatched" : 6, "nUpserted" : 0, "nModified" : 6 })
```

```go:go
selector := bson.M{"$and": []interface{}{
  bson.M{"no_in_series": bson.M{"$gte": 50}},
  bson.M{"no_in_series": bson.M{"$lte": 55}}},
}
update := bson.M{"$set": bson.M{"season": 9}}
changeInfo, err := cl.UpdateAll(selector, update)
if err != nil {
  if mgo.IsDup(err) {
    fmt.Printf("Duplicate key error \n")
  }
  if v, ok := err.(*mgo.LastError); ok {
    fmt.Printf("Code:%d N:%d UpdatedExisting:%t WTimeout:%t Waited:%d \n", v.Code, v.N, v.UpdatedExisting, v.WTimeout, v.Waited)
  } else {
    fmt.Printf("%+v \n", err)
  }
}
if changeInfo != nil {
  fmt.Printf("%+v \n", changeInfo)
  // ⇒ &{Updated:6 Removed:0 UpsertedId:<nil>}
}
```

**ObjectIdを指定して更新します**

例) ObjectIdで指定するドキュメントの放送日(original_air_date)を更新します。

```js:mongo_shell
> db.columbo.update({_id:ObjectId("556f1a1fafaf9f0864000012")},{$set:{original_air_date:"February 27, 1989"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
```

```go:go
id := bson.ObjectIdHex("556ce9b2f5c33ee8cd7ea852")
update := bson.M{"$set": bson.M{"original_air_date": "February 27, 1989"}}
err := cl.UpdateId(id, update)
if err != nil {
  if mgo.IsDup(err) {
    fmt.Printf("Duplicate key error \n")
  }
  if v, ok := err.(*mgo.LastError); ok {
    fmt.Printf("Code:%d N:%d UpdatedExisting:%t WTimeout:%t Waited:%d \n", v.Code, v.N, v.UpdatedExisting, v.WTimeout, v.Waited)
  } else {
    fmt.Printf("%+v \n", err)
  }
}
```

> GoDOc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Collection.Update](http://godoc.org/labix.org/v2/mgo#Collection.Update)       |`func (c *Collection) Update(selector interface{}, update interface{}) error` |
|[Collection.UpdateAll](http://godoc.org/labix.org/v2/mgo#Collection.UpdateAll) |`func (c *Collection) UpdateAll(selector interface{}, update interface{}) (info *ChangeInfo, err error)` |
|[Collection.UpdateId](http://godoc.org/labix.org/v2/mgo#Collection.UpdateId)   |`func (c *Collection) UpdateId(id interface{}, update interface{}) error` |
|ErrNotFound                                                           |`var ErrNotFound = errors.New("not found")`|


#### 追加 or 更新 (Upsert, UpsertId)

**追加・更新を行います**

事前に対象になるドキュメントを削除しておきます。
コレクションに無いドキュメントをupsertモードで追加し、その後そのドキュメントのフィールドを更新します。

```js:mongo_shell
> db.columbo.remove({season:8})

> db.columbo.update(
  {title:"Columbo Goes to the Guillotine"},
  {title:"Columbo Goes to the Guillotine",  runtime:93, guest_staring:"Anthony Andrews", guest_staring_role:"Elliott Blake, A psychic",                 directed_by:"Leo Penn",      written_by:["William Read Woodfield"], teleplay:[""], season:8, no_in_season:1, no_in_series:46, japanese_title:"汚れた超能力", japanese_air_date:ISODate("1993-05-07T00:00:00+0900")},
  {upsert:true}
)
WriteResult({
        "nMatched" : 0,
        "nUpserted" : 1,
        "nModified" : 0,
        "_id" : ObjectId("557090f515cc230577dd7eac")
})

> db.columbo.update(
  {title: "Columbo Goes to the Guillotine"},
  {$set:{original_air_date:"February 27, 1989"}},
  {upsert:true}
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
```

```go:go
// season 8 all delete
ci, err := cl.RemoveAll(bson.M{"season": 8})
if err != nil {
  fmt.Printf("%+v \n", err)
}

// コレクションに存在しないドキュメントをupsertで追加します
lc, _ := time.LoadLocation("Asia/Tokyo")
selector := bson.M{"title": "Columbo Goes to the Guillotine"}
columbo := Columbo{ID: bson.NewObjectId(), Title: "Columbo Goes to the Guillotine", Runtime: 93, GuestStaring: "Anthony Andrews", GuestStaringRole: "Elliott Blake, A psychic", DirectedBy: "Leo Penn", WrittenBy: []string{"William Read Woodfield"}, Teleplay: []string{""}, Season: 8, NoInSeason: 1, NoInSeries: 46, JapaneseTitle: "汚れた超能力", JapaneseAirDate: time.Date(1993, 5, 7, 0, 0, 0, 0, lc)}
ci, err = cl.Upsert(selector, &columbo)
if err != nil {
  fmt.Printf("%+v \n", err)
}
if ci != nil {
  fmt.Printf("%+v \n", ci)
  // ⇒ &{Updated:0 Removed:0 UpsertedId:ObjectIdHex("55709323afaf9f019000001b")}
}

// upsertでフィールドを更新します
update := bson.M{"$set": bson.M{"original_air_date": "February 27, 1989"}}
ci, err = cl.Upsert(selector, update)
if err != nil {
  fmt.Printf("%+v \n", err)
}
if ci != nil {
  fmt.Printf("%+v \n", ci)
  // ⇒ &{Updated:1 Removed:0 UpsertedId:<nil>}
}
```

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Collection.Upsert](http://godoc.org/labix.org/v2/mgo#Collection.Upsert)     |`func (c *Collection) Upsert(selector interface{}, update interface{}) (info *ChangeInfo, err error)` |
|[Collection.UpsertId](http://godoc.org/labix.org/v2/mgo#Collection.UpsertId) |`func (c *Collection) UpsertId(id interface{}, update interface{}) (info *ChangeInfo, err error)` |

#### 削除 (Remove, RemoveId)

**条件を指定して1件削除します**

例) シーズン8のエピソードを1件削除します。（どのエピソードかは不定です。）

```js:mongo_shell
> db.columbo.remove({season:8}, {justOne:true})
WriteResult({ "nRemoved" : 0 })
```

```go:go
selector := bson.M{"season": 8}
err := cl.Remove(selector)
if err != nil {
  if v, ok := err.(*mgo.LastError); ok {
    fmt.Printf("Code:%d N:%d UpdatedExisting:%t WTimeout:%t Waited:%d \n", v.Code, v.N, v.UpdatedExisting, v.WTimeout, v.Waited)
  } else {
    fmt.Printf("%+v \n", err)
  }
}
```

セッションがセーフモードの場合、条件にあうドキュメントが見つからなかった場合は`ErrNotFound`が返ります。
それ以外のエラーのときerrはLastError型になります。

**条件にあうドキュメントを全て削除します**

例) シーズン8のエピソードをすべて削除します。

```js:mongo_shell
> db.columbo.remove({season:8})
```

```go:go
selector := bson.M{"season": 8}
changeInfo, err := cl.RemoveAll(selector)
if err != nil {
  if v, ok := err.(*mgo.LastError); ok {
    fmt.Printf("Code:%d N:%d UpdatedExisting:%t WTimeout:%t Waited:%d \n", v.Code, v.N, v.UpdatedExisting, v.WTimeout, v.Waited)
  } else {
    fmt.Printf("%+v \n", err)
  }
if changeInfo != nil {
  fmt.Printf("Removed:%d, Updated:%d \n", changeInfo.Removed, changeInfo.Updated)
}
```

セッションがセーフモードのときのerrはLastError型です。

**無条件に全件削除します**

例) コレクションのドキュメントをすべて削除します。

```js:mongo_shell
> db.columbo.remove({})
WriteResult({ "nRemoved" : 55 })
```

```go:go
changeInfo, err := cl.RemoveAll(nil)
if err != nil {
  if v, ok := err.(*mgo.LastError); ok {
    fmt.Printf("Code:%d N:%d UpdatedExisting:%t WTimeout:%t Waited:%d \n", v.Code, v.N, v.UpdatedExisting, v.WTimeout, v.Waited)
  } else {
    fmt.Printf("%+v \n", err)
  }
}
if changeInfo != nil {
  fmt.Printf("Removed:%d, Updated:%d \n", changeInfo.Removed, changeInfo.Updated)
  // ⇒ Removed:55, Updated:0
}
```

**ObjectIdを指定して削除します**

```js:mongo_shell
> db.columbo.remove({_id:ObjectId("556f1a1fafaf9f0864000012")})
WriteResult({ "nRemoved" : 1 })
```

```go:go
id := bson.ObjectIdHex("556ce9b2f5c33ee8cd7ea852")
err := cl.RemoveId(id)
if err != nil {
  if v, ok := err.(*mgo.LastError); ok {
    fmt.Printf("Code:%d N:%d UpdatedExisting:%t WTimeout:%t Waited:%d \n", v.Code, v.N, v.UpdatedExisting, v.WTimeout, v.Waited)
  } else {
    fmt.Printf("RemoveId: %+v \n", err)
  }
}
```

RemoveIdは下記のRemoveと同じ意味になります。

```go:go
id := bson.ObjectIdHex("556ce9b2f5c33ee8cd7ea852")
err := cl.Remove(bson.M{"_id": id})
```

> GoDoc
>
>|name                                                                |definition    |
|:--------------------------------------------------------------------|:-------------|
|[Collection.Remove](http://godoc.org/labix.org/v2/mgo#Collection.Remove)       |`func (c *Collection) Remove(selector interface{}) error` | 
|[Collection.RemoveId](http://godoc.org/labix.org/v2/mgo#Collection.RemoveId)   |`func (c *Collection) RemoveId(id interface{}) error` |
|[Collection.RemoveAll](http://godoc.org/labix.org/v2/mgo#Collection.RemoveAll) |`func (c *Collection) RemoveAll(selector interface{}) (info *ChangeInfo, err error)` |
|[ErrNotFound]()||

## 付録

### A. サンプルデータ作成スクリプト

シーズン0からシーズン7までのデータを作成します。

```js:mongo_shell
> db.columbo.drop()
false

> db.columbo.insert([
{title:"Prescription: Murder",                original_air_date:"February 20, 1968",   runtime:98, guest_staring:"Gene Barry",        guest_staring_role:"Dr. Ray Fleming (Gene Barry), a psychiatrist",  directed_by:"Richard Irving",       written_by:["Richard Levinson & William Link"],                  teleplay:[""],                              season:0, no_in_season:1, no_in_series:1,  japanese_title:"殺人処方箋",                     japanese_air_date:ISODate("1972-08-27T00:00:00+09:00")},
{title:"Ransom for a Dead Man",               original_air_date:"March 1, 1971",       runtime:98, guest_staring:"Lee Grant",         guest_staring_role:"Leslie Williams, a brilliant lawyer and pilot", directed_by:"Richard Irving",       written_by:["Richard Levinson & William Link"],                  teleplay:["Dean Hargrove"],                 season:0, no_in_season:2, no_in_series:2,  japanese_title:"死者の身代金",                   japanese_air_date:ISODate("1973-04-22T00:00:00+09:00")},
{title:"Murder by the Book",                  original_air_date:"September 15, 1971",  runtime:73, guest_staring:"Jack Cassidy",      guest_staring_role:"Ken Franklin is one half of a mystery writing team", directed_by:"Steven Spielberg",     written_by:["Steven Bochco"],                                    teleplay:[""],                              season:1, no_in_season:1, no_in_series:3,  japanese_title:"構想の死角",                japanese_air_date:ISODate("1972-11-26T00:00:00+09:00")},
{title:"Death Lends a Hand",                  original_air_date:"October 6, 1971",     runtime:73, guest_staring:"Robert Culp",       guest_staring_role:"Carl Brimmer, The head of a private detective agency",directed_by:"Bernard L. Kowalski",  written_by:["RRichard Levinson & William Link"],                 teleplay:[""],                              season:1, no_in_season:2, no_in_series:4,  japanese_title:"指輪の爪あと",             japanese_air_date:ISODate("1973-01-21T00:00:00+09:00")},
{title:"Dead Weight",                         original_air_date:"October 27, 1971",    runtime:73, guest_staring:"Eddie Albert",      guest_staring_role:"Major General Martin Hollister, a retired Marine Corps war hero",               directed_by:"Jack Smight",          written_by:["John T. Dugan"],                                    teleplay:[""],                              season:1, no_in_season:3, no_in_series:5,  japanese_title:"ホリスター将軍のコレクション", japanese_air_date:ISODate("1972-09-24T00:00:00+09:00")},
{title:"Suitable for Framing",                original_air_date:"November 17, 1971",   runtime:73, guest_staring:"Ross Martin",       guest_staring_role:"Dale Kingston, Art critic",                     directed_by:"Hy Averback",          written_by:["Jackson Gillis"],                                   teleplay:[""],                              season:1, no_in_season:4, no_in_series:6,  japanese_title:"二枚のドガの絵",                 japanese_air_date:ISODate("1972-10-22T00:00:00+09:00")},
{title:"Lady in Waiting",                     original_air_date:"December 15, 1971",   runtime:73, guest_staring:"Susan Clark",       guest_staring_role:"Beth Chadwick, sister of domineering, Bryce",   directed_by:"Norman Lloyd",         written_by:["Barney Slater"],                                    teleplay:["Steven Bochco"],                 season:1, no_in_season:5, no_in_series:7,  japanese_title:"もう一つの鍵",                   japanese_air_date:ISODate("1972-12-17T00:00:00+09:00")},
{title:"Short Fuse",                          original_air_date:"January 19, 1972",    runtime:73, guest_staring:"Roddy McDowall",    guest_staring_role:"Roger Stanford, A chemist",                     directed_by:"Edward M. Abrams",     written_by:["Lester & Tina Pine","Jackson Gillis"],              teleplay:["Jackson Gillis"],                season:1, no_in_season:6, no_in_series:8,  japanese_title:"死の方程式",                     japanese_air_date:ISODate("1973-03-18T00:00:00+09:00")},
{title:"Blueprint for Murder",                original_air_date:"February 9, 1972",    runtime:73, guest_staring:"Patrick O'Neal",    guest_staring_role:"Elliot Markham, An architect",                  directed_by:"Peter Falk",           written_by:["William Kelley"],                                   teleplay:["Steven Bochco"],                 season:1, no_in_season:7, no_in_series:9,  japanese_title:"パイルD-3の壁",                  japanese_air_date:ISODate("1973-02-25T00:00:00+09:00")},
{title:"Étude in Black",                      original_air_date:"September 17, 1972",  runtime:98, guest_staring:"John Cassavetes",   guest_staring_role:"Alex Benedict, The conductor of the Los Angeles Philharmonic Orchestra",  directed_by:"Nicholas Colasanto",   written_by:["Richard Levinson & William Link"],      teleplay:["Steven Bochco"],                 season:2, no_in_season:1, no_in_series:10, japanese_title:"黒のエチュード",   japanese_air_date:ISODate("1973-09-30T00:00:00+09:00")},
{title:"The Greenhouse Jungle",               original_air_date:"October 15, 1972",    runtime:73, guest_staring:"Ray Milland",       guest_staring_role:"Jarvis Goodland, An expert in orchids",         directed_by:"Boris Sagal",          written_by:["Jonathan Latimer"],                                 teleplay:[""],                              season:2, no_in_season:2, no_in_series:11, japanese_title:"悪の温室",                       japanese_air_date:ISODate("1973-05-27T00:00:00+09:00")},
{title:"The Most Crucial Game",               original_air_date:"November 5, 1972",    runtime:73, guest_staring:"Robert Culp",       guest_staring_role:"Paul Hanlon, The general manager of the Los Angeles Rockets football team",  directed_by:"Jeremy Kagan",         written_by:["John T. Dugan"],                   teleplay:[""],                              season:2, no_in_season:3, no_in_series:12, japanese_title:"アリバイのダイヤル", japanese_air_date:ISODate("1973-06-24T00:00:00+09:00")},
{title:"Dagger of the Mind",                  original_air_date:"November 26, 1972",   runtime:98, guest_staring:"Richard Basehart",  guest_staring_role:"Actors Nicholas Framer and his wife, Lillian Stanhope", directed_by:"Richard Quine",        written_by:["Richard Levinson & William Link"],                  teleplay:["Jackson Gillis"],                season:2, no_in_season:4, no_in_series:13, japanese_title:"ロンドンの傘",           japanese_air_date:ISODate("1973-07-29T00:00:00+09:00")},
{title:"Requiem for a Falling Star",          original_air_date:"January 21, 1973",    runtime:73, guest_staring:"Anne Baxter",       guest_staring_role:"movie star Nora Chandler",                     directed_by:"Richard Quine",        written_by:["Jackson Gillis"],                          teleplay:[""],                              season:2, no_in_season:5, no_in_series:14, japanese_title:"偶像のレクイエム",                         japanese_air_date:ISODate("1973-08-26T00:00:00+09:00")},
{title:"A Stitch in Crime",                   original_air_date:"February 11, 1973",   runtime:73, guest_staring:"Leonard Nimoy",     guest_staring_role:"Cardiac surgeon Dr. Barry Mayfield",           directed_by:"Hy Averback",          written_by:["Shirl Hendryx"],                                    teleplay:[""],                              season:2, no_in_season:6, no_in_series:15, japanese_title:"溶ける糸",                        japanese_air_date:ISODate("1973-10-28T00:00:00+09:00")},
{title:"The Most Dangerous Match",            original_air_date:"March 4, 1973",       runtime:73, guest_staring:"Laurence Harvey",   guest_staring_role:"Chess Grandmaster Emmett Clayton",             directed_by:"Edward M. Abroms",     written_by:["Jackson Gillis","Richard Levinson & William Link"], teleplay:["Jackson Gillis"],                season:2, no_in_season:7, no_in_series:16, japanese_title:"断たれた音",                      japanese_air_date:ISODate("1973-11-25T00:00:00+09:00")},
{title:"Double Shock",                        original_air_date:"March 25, 1973",      runtime:73, guest_staring:"Martin Landau",     guest_staring_role:"Flamboyant television chef Dexter Paris and his twin brother, conservative banker Norman",  directed_by:"Robert Butler",        written_by:["Jackson Gillis","Richard Levinson & William Link"], teleplay:["Steven Bochco"],  season:2, no_in_season:8, no_in_series:17, japanese_title:"二つの顔", japanese_air_date:ISODate("1973-12-23T00:00:00+09:00")},
{title:"Lovely But Lethal",                   original_air_date:"September 23, 1973",  runtime:73, guest_staring:"Vera Miles",        guest_staring_role:"Cosmetics queen Viveca Scott",                 directed_by:"Jeannot Szwarc",       written_by:["Myrna Bercovici"],                                  teleplay:["Jackson Gillis"],                season:3, no_in_season:1, no_in_series:18, japanese_title:"毒のある花",                      japanese_air_date:ISODate("1974-09-14T00:00:00+09:00")},
{title:"Any Old Port in a Storm",             original_air_date:"October 7, 1973",     runtime:98, guest_staring:"Donald Pleasence",  guest_staring_role:"Wine connoisseur Adrian Carsini",              directed_by:"Leo Penn",             written_by:["Larry Cohen"],                                      teleplay:["Stanley Ralph Ross"],            season:3, no_in_season:2, no_in_series:19, japanese_title:"別れのワイン",                    japanese_air_date:ISODate("1974-06-29T00:00:00+09:00")},
{title:"Candidate for Crime",                 original_air_date:"November 4, 1973",    runtime:98, guest_staring:"Jackie Cooper",     guest_staring_role:"Nelson Hayward, is coercing the womanizing senatorial candidate",  directed_by:"Boris Sagal",          written_by:["Larry Cohen"],                                      teleplay:["Irving Pearlberg & Alvin R. Friedman","Roland Kibbee & Dean Hargrove"], season:3, no_in_season:3, no_in_series:20, japanese_title:"野望の果て", japanese_air_date:ISODate("1974-08-17T00:00:00+09:00")},
{title:"Double Exposure",                     original_air_date:"December 16, 1973",   runtime:73, guest_staring:"Robert Culp",       guest_staring_role:"Dr. Bart Keppel, A motivation research specialist",  directed_by:"Richard Quine",        written_by:["Stephen J. Cannell"],                               teleplay:[""],                              season:3, no_in_season:4, no_in_series:21, japanese_title:"意識の下の映像",            japanese_air_date:ISODate("1974-08-10T00:00:00+09:00")},
{title:"Publish or Perish",                   original_air_date:"January 18, 1974",    runtime:73, guest_staring:"Jack Cassidy",      guest_staring_role:"Riley Greenleaf, Publisher",                   directed_by:"Robert Butler",        written_by:["Peter S. Fischer"],                                 teleplay:[""],                              season:3, no_in_season:5, no_in_series:22, japanese_title:"第三の終章",                      japanese_air_date:ISODate("1974-12-14T00:00:00+09:00")},
{title:"Mind Over Mayhem",                    original_air_date:"February 10, 1974",   runtime:73, guest_staring:"José Ferrer",       guest_staring_role:"Dr. Marshall Cahill, director of a high-tech Pentagon think tank",  directed_by:"Alf Kjellin",          written_by:["Robert Specht"],                                    teleplay:["Steven Bochco","Dean Hargrove & Roland Kibbee"], season:3, no_in_season:6, no_in_series:23, japanese_title:"愛情の計算", japanese_air_date:ISODate("1974-08-31T00:00:00+09:00")},
{title:"Swan Song",                           original_air_date:"March 3, 1974",       runtime:98, guest_staring:"Johnny Cash",       guest_staring_role:"Gospel-singing superstar Tommy Brown",         directed_by:"Nicholas Colasanto",   written_by:["Stanley Ralph Ross"],                               teleplay:["David Rayfiel"],                 season:3, no_in_season:7, no_in_series:24, japanese_title:"白鳥の歌",                        japanese_air_date:ISODate("1974-09-21T00:00:00+09:00")},
{title:"A Friend in Deed",                    original_air_date:"May 5, 1974",         runtime:98, guest_staring:"Richard Kiley",     guest_staring_role:"Deputy police commissioner Mark Halperin",     directed_by:"Ben Gazzara",          written_by:["Peter S. Fischer"],                                 teleplay:[""],                              season:3, no_in_season:8, no_in_series:25, japanese_title:"権力の墓穴",                      japanese_air_date:ISODate("1974-10-05T00:00:00+09:00")},
{title:"An Exercise in Fatality",             original_air_date:"September 15, 1974",  runtime:98, guest_staring:"Robert Conrad",     guest_staring_role:"Renowned exercise guru Milo Janus",            directed_by:"Bernard L. Kowalski",  written_by:["Larry Cohen"],                                      teleplay:["Peter S. Fischer"],              season:4, no_in_season:1, no_in_series:26, japanese_title:"自縛の紐",                        japanese_air_date:ISODate("1975-12-27T00:00:00+09:00")},
{title:"Negative Reaction",                   original_air_date:"October 6, 1974",     runtime:98, guest_staring:"Dick Van Dyke",     guest_staring_role:"professional photographer Paul Galesko",       directed_by:"Alf Kjellin",          written_by:["Peter S. Fischer"],                                 teleplay:[""],                              season:4, no_in_season:2, no_in_series:27, japanese_title:"逆転の構図",                      japanese_air_date:ISODate("1975-12-20T00:00:00+09:00")},
{title:"By Dawn's Early Light",               original_air_date:"October 27, 1974",    runtime:98, guest_staring:"Patrick McGoohan",  guest_staring_role:"Colonel Lyle C. Rumford, head of the Haynes Military Academy",    directed_by:"Harvey Hart",          written_by:["Howard Berk"],                                      teleplay:[""],                              season:4, no_in_season:3, no_in_series:28, japanese_title:"祝砲の挽歌",   japanese_air_date:ISODate("1976-01-10T00:00:00+09:00")},
{title:"Troubled Waters",                     original_air_date:"February 9, 1975",    runtime:98, guest_staring:"Robert Vaughn",     guest_staring_role:"Auto executive Hayden Danziger",               directed_by:"Ben Gazzara",          written_by:["Jackson Gillis","William Driskill"],                teleplay:["William Driskill"],              season:4, no_in_season:4, no_in_series:29, japanese_title:"歌声の消えた海",                  japanese_air_date:ISODate("1976-01-03T00:00:00+09:00")},
{title:"Playback",                            original_air_date:"March 2, 1975",       runtime:73, guest_staring:"Oskar Werner",      guest_staring_role:"Harold Van Wick, the gadget-obsessed president of Midas Electronics",  directed_by:"Bernard L. Kowalski",  written_by:["David P. Lewis & Booker T. Bradshaw"],       teleplay:[""],                              season:4, no_in_season:5, no_in_series:30, japanese_title:"ビデオテープの証言", japanese_air_date:ISODate("1976-12-11T00:00:00+09:00")},
{title:"A Deadly State of Mind",              original_air_date:"April 27, 1975",      runtime:73, guest_staring:"George Hamilton",   guest_staring_role:"Psychiatrist Dr. Mark Collier",                directed_by:"Harvey Hart",          written_by:["Peter S. Fischer"],                                 teleplay:[""],                              season:4, no_in_season:6, no_in_series:31, japanese_title:"5時30分の目撃者",                 japanese_air_date:ISODate("1976-12-18T00:00:00+09:00")},
{title:"Forgotten Lady",                      original_air_date:"September 14, 1975",  runtime:85, guest_staring:"Janet Leigh",       guest_staring_role:"Aging former movie star Grace Wheeler",  directed_by:"Harvey Hart",          written_by:["Bill Driskill"],                                          teleplay:[""],                              season:5, no_in_season:1, no_in_series:32, japanese_title:"忘れられたスター",                japanese_air_date:ISODate("1977-01-03T00:00:00+09:00")},
{title:"A Case of Immunity",                  original_air_date:"October 12, 1975",    runtime:73, guest_staring:"Héctor Elizondo",   guest_staring_role:"Hassan Salah, chief diplomat of the Legation of Swahari",    directed_by:"Ted Post",             written_by:["James Menzies"],                                    teleplay:["Lou Shaw"],                      season:5, no_in_season:2, no_in_series:33, japanese_title:"ハッサン・サラーの反逆", japanese_air_date:ISODate("1976-12-25T00:00:00+09:00")},
{title:"Identity Crisis",                     original_air_date:"November 2, 1975",    runtime:98, guest_staring:"Patrick McGoohan",  guest_staring_role:"speech-writing consultant Nelson Brenner",     directed_by:"Patrick McGoohan",     written_by:["Bill Driskill"],                                    teleplay:[""],                              season:5, no_in_season:3, no_in_series:34, japanese_title:"仮面の男",                        japanese_air_date:ISODate("1977-09-24T00:00:00+09:00")},
{title:"A Matter of Honor",                   original_air_date:"February 1, 1976",    runtime:73, guest_staring:"Ricardo Montalban", guest_staring_role:"Luis Montoya, A Mexican national hero",        directed_by:"Ted Post",             written_by:["Brad Radnitz"],                                     teleplay:[""],                              season:5, no_in_season:4, no_in_series:35, japanese_title:"闘牛士の栄光",                    japanese_air_date:ISODate("1977-10-01T00:00:00+09:00")},
{title:"Now You See Him...",                  original_air_date:"February 29, 1976",   runtime:85, guest_staring:"Jack Cassidy",      guest_staring_role:"Great Santini, a magician extraordinaire",     directed_by:"Harvey Hart",          written_by:["Michael Sloan"],                                    teleplay:[""],                              season:5, no_in_season:5, no_in_series:36, japanese_title:"魔術師の幻想",                    japanese_air_date:ISODate("1977-12-31T00:00:00+09:00")},
{title:"Last Salute to the Commodore",        original_air_date:"May 2, 1976",         runtime:98, guest_staring:"Robert Vaughn",     guest_staring_role:"Son-in-law Charles Clay",                      directed_by:"Patrick McGoohan",     written_by:["Jackson Gillis"],                                   teleplay:[""],                              season:5, no_in_season:6, no_in_series:37, japanese_title:"さらば提督",                      japanese_air_date:ISODate("1977-10-08T00:00:00+09:00")},
{title:"Fade in to Murder",                   original_air_date:"October 10, 1976",    runtime:73, guest_staring:"William Shatner",   guest_staring_role:"Egocentric actor Ward Fowler",                 directed_by:"Bernard L. Kowalski",  written_by:["Henry Garson"],                                     teleplay:["Lou Shaw","Peter S. Feibleman"], season:6, no_in_season:1, no_in_series:38, japanese_title:"ルーサン警部の犯罪",              japanese_air_date:ISODate("1977-12-17T00:00:00+09:00")},
{title:"Old Fashioned Murder",                original_air_date:"November 28, 1976",   runtime:73, guest_staring:"Joyce Van Patten",  guest_staring_role:"Ruth Lytton, Owner of the Lytton Museum",      directed_by:"Robert Douglas",       written_by:["Lawrence Vail"],                                    teleplay:["Peter S. Feibleman"],            season:6, no_in_season:2, no_in_series:39, japanese_title:"黄金のバックル",                  japanese_air_date:ISODate("1977-12-24T00:00:00+09:00")},
{title:"The Bye-Bye Sky High IQ Murder Case", original_air_date:"May 22, 1977",        runtime:73, guest_staring:"Theodore Bikel",    guest_staring_role:"Oliver Brandt, a senior partner in an accounting firm",  directed_by:"Sam Wanamaker",        written_by:["Robert Malcolm Young"],                   teleplay:[""],                              season:6, no_in_season:3, no_in_series:40, japanese_title:"殺しの序曲",                      japanese_air_date:ISODate("1978-05-20T00:00:00+09:00")},
{title:"Try and Catch Me",                    original_air_date:"November 21, 1977",   runtime:73, guest_staring:"Ruth Gordon",       guest_staring_role:"Mystery author Abigail Mitchell",              directed_by:"James Frawley",        written_by:["Gene Thompson"],                                    teleplay:["Gene Thompson & Paul Tuckahoe"], season:7, no_in_season:1, no_in_series:41, japanese_title:"死者のメッセージ",                japanese_air_date:ISODate("1978-04-08T00:00:00+09:00")},
{title:"Murder Under Glass",                  original_air_date:"January 30, 1978",    runtime:73, guest_staring:"Louis Jourdan",     guest_staring_role:"Renowned restaurant critic Paul Gerard",       directed_by:"Jonathan Demme",       written_by:["Robert van Scoyk"],                                 teleplay:[""],                              season:7, no_in_season:2, no_in_series:42, japanese_title:"美食の報酬",                      japanese_air_date:ISODate("1978-05-27T00:00:00+09:00")},
{title:"Make Me a Perfect Murder",            original_air_date:"February 28, 1978",   runtime:98, guest_staring:"Trish Van Devere",  guest_staring_role:"TV programmer Kay Freestone",                  directed_by:"James Frawley",        written_by:["Robert Blees"],                                     teleplay:[""],                              season:7, no_in_season:3, no_in_series:43, japanese_title:"秒読みの殺人",                    japanese_air_date:ISODate("1979-01-02T00:00:00+09:00")},
{title:"How to Dial a Murder",                original_air_date:"April 15, 1978",      runtime:73, guest_staring:"Nicol Williamson",  guest_staring_role:"Mind control seminar guru Dr. Eric Mason",     directed_by:"James Frawley",        written_by:["Anthony Lawrence"],                                 teleplay:["Tom Lazarus"],                   season:7, no_in_season:4, no_in_series:44, japanese_title:"攻撃命令",                        japanese_air_date:ISODate("1979-01-04T00:00:00+09:00")},
{title:"The Conspirators",                    original_air_date:"May 13, 1978",        runtime:98, guest_staring:"Clive Revill",      guest_staring_role:"Famous Irish poet and author Joe Devlin",      directed_by:"Leo Penn",             written_by:["Howard Berk"],                                      teleplay:[""],                              season:7, no_in_season:5, no_in_series:45, japanese_title:"策謀の結末",                      japanese_air_date:ISODate("1979-01-03T00:00:00+09:00"), based_on_an_idea_by: "Pat Robison"}
])
WriteResult({
    "writeErrors" : [ ],
    "writeConcernErrors" : [ ],
    "nInserted" : 45,
    "nUpserted" : 0,
    "nMatched" : 0,
    "nModified" : 0,
    "nRemoved" : 0,
    "upserted" : [ ]

> db.columbo.find().count()
45
```