Edited at

mgoの基本的な操作まとめ

More than 3 years have passed since last update.


概要

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

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


mgoの準備


インストール

> go get gopkg.in/mgo.v2


参考サイト

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

mgo GoDoc

MongoDB manual

MongoDB blog


サンプルデータの準備

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


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に記載しています。)


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

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

session, err := mgo.Dial("localhost:27017")

if err != nil {
panic(err)
}
defer session.Close()

db := session.DB("sample")


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


example

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


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

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


DialWithTimeout

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

DialWithTimeout()DialWithInfo()のラッパーメソッドです。

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


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

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
func Dial(url string) (*Session, error)

DialWithTimeout
func DialWithTimeout(url string, timeout time.Duration) (*Session, error)

DialWithInfo
func DialWithInfo(info *DialInfo) (*Session, error)

DialInfo
type DialInfo struct


Sessionについて

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


New()

オリジナルのセッションと同じパラメータ(一貫性(consistency)、バッチサイズ(batch size)、プリフェッチサイズ(prefetching)、セーフティーモード(safety mode)を含む)で新しいセッションを作成します。

ただし認証情報(Credential)はコピーしません。またオリジナルのセッションとは別に新しいソケットを作成します。



source

func (s *Session) New() *Session {

s.m.Lock()
scopy := copySession(s, false)
s.m.Unlock()
scopy.Refresh()
return scopy
}



Copy()

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



source

func (s *Session) Copy() *Session {

s.m.Lock()
scopy := copySession(s, true)
s.m.Unlock()
scopy.Refresh()
return scopy
}



Clone()

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



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

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

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

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
type Credential struct


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


go

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


         +-[ 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
type Session struct

Session.DB
func (s *Session) DB(name string) *Database

Session.New
func (s *Session) New() *Session

Session.Copy
func (s *Session) Copy() *Session

Session.Clone
func (s *Session) Clone() *Session

Session.Close
func (s *Session) Close()


SetMode()

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


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はそのまま、セカンダリーへ接続不可



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
func (s *Session) SetMode(consistency mode, refresh bool)

Session.Mode
func (s *Session) Mode() mode

Session.Refresh
func (s *Session) Refresh()


SetSafe()

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

Unacknowledged

完全にエラーの検証を無効にします。

更新処理の成否を確認しませんので高速に動作します。


go

session.SetSafe(nil)



go

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


Acknowledged

デフォルトのモードです。

更新処理のエラーの検証を行います。このためgetLastErrorコマンドが実行されます。


go

session.SetSafe(&mgo.Safe{})



go

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


Journaled

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


go

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


Replica Acknowledged

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


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
func (s *Session) SetSafe(safe *Safe)

Session.Safe
func (s *Session) Safe() (safe *Safe)

Safe
type Safe struct


SetDebug()

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

Loggerへデバッグログを出力します。

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


go

logger := log.New(os.Stdout, "MGO: ", log.Lshortfile)

mgo.SetDebug(true)
mgo.SetLogger(logger)


GoDoc

name
definition

SetDebug
func SetDebug(debug bool)

SetLogger
func SetLogger(logger log_Logger)


データベースの操作


コレクションの取得

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


mongo_shell

> use sample

switched to db sample

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



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
type Database struct

Database.C
func (db *Database) C(name string) *Collection

Database.CollectionNames
func (db *Database) CollectionNames() (names []string, err error)

Collection
type Collection struct

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

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


mongo_shell

> db.createCollection("columbo",{capped:true, size:1073741824, max:1000000})

{ "ok" : 1 }


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
func (c *Collection) Create(info *CollectionInfo) error

CollectionInfo
type CollectionInfo struct

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

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


mongo_shell

> db.columbo.createIndex({no_in_series:1}, {unique:true, name:"columbo_uni01"})

{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}

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


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
type Index struct

EnsureIndex
func (c *Collection) EnsureIndex(index Index) error


ユーザーの操作

ユーザーの作成と削除


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

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
func (db *Database) RemoveUser(user string) error

Database.UpsertUser
func (db *Database) UpsertUser(user *User) error

User
type User struct

Role
type Role string

Database.Login
func (db *Database) Login(user, pass string) error

Database.Logout
func (db *Database) Logout()


コレクションの操作

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


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のエピソードを指定して検索します。


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

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
func (c *Collection) Find(query interface{}) *Query

Query.Select
func (q *Query) Select(selector interface{}) *Query

Query.All
func (q *Query) All(result interface{}) error

Iter.All
func (iter *Iter) All(result interface{}) error

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

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


mongo_shell

> db.columbo.find().skip(10).limit(5)



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
func (q *Query) Limit(n int) *Query

Query.Skip
func (q *Query) Skip(n int) *Query

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

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


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

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)が新しい順に並べ替えます。


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

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
func (q *Query) Sort(fields ...string) *Query

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

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


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

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
type RegEx struct

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

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


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

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

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
func (q *Query) One(result interface{}) (err error)

QueryError
type QueryError struct

ObjectIdを指定して検索します


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

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

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


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

特定の型を使用しない方法です。

検索するドキュメントのスキーマが不定の場合などで使用できます。


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

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
func (c *Collection) FindId(id interface{}) *Query

ObjectIdHex
func ObjectIdHex(s string) ObjectId


追加 (Insert,Bulk)

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

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


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

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
func (c *Collection) Insert(docs ...interface{}) error

IsDup
func IsDup(err error) bool

LastError
type LastError struct

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

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


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

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インサートで追加します。


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

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

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
type Bulk struct

Bulk.Insert
func (b *Bulk) Insert(docs ...interface{})

Bulk.Run
func (b *Bulk) Run() (*BulkResult, error)

BulkResult
type BulkResult struct


更新 (Update, UpdateId)

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

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


mongo_shell

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


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


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として更新します。


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

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)を更新します。


mongo_shell

> db.columbo.update({_id:ObjectId("556f1a1fafaf9f0864000012")},{$set:{original_air_date:"February 27, 1989"}})

WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })


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
func (c *Collection) Update(selector interface{}, update interface{}) error

Collection.UpdateAll
func (c *Collection) UpdateAll(selector interface{}, update interface{}) (info *ChangeInfo, err error)

Collection.UpdateId
func (c *Collection) UpdateId(id interface{}, update interface{}) error

ErrNotFound
var ErrNotFound = errors.New("not found")


追加 or 更新 (Upsert, UpsertId)

追加・更新を行います

事前に対象になるドキュメントを削除しておきます。

コレクションに無いドキュメントをupsertモードで追加し、その後そのドキュメントのフィールドを更新します。


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

// 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
func (c *Collection) Upsert(selector interface{}, update interface{}) (info *ChangeInfo, err error)

Collection.UpsertId
func (c *Collection) UpsertId(id interface{}, update interface{}) (info *ChangeInfo, err error)


削除 (Remove, RemoveId)

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

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


mongo_shell

> db.columbo.remove({season:8}, {justOne:true})

WriteResult({ "nRemoved" : 0 })


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のエピソードをすべて削除します。


mongo_shell

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



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型です。

無条件に全件削除します

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


mongo_shell

> db.columbo.remove({})

WriteResult({ "nRemoved" : 55 })


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を指定して削除します


mongo_shell

> db.columbo.remove({_id:ObjectId("556f1a1fafaf9f0864000012")})

WriteResult({ "nRemoved" : 1 })


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

id := bson.ObjectIdHex("556ce9b2f5c33ee8cd7ea852")

err := cl.Remove(bson.M{"_id": id})


GoDoc

name
definition

Collection.Remove
func (c *Collection) Remove(selector interface{}) error

Collection.RemoveId
func (c *Collection) RemoveId(id interface{}) error

Collection.RemoveAll
func (c *Collection) RemoveAll(selector interface{}) (info *ChangeInfo, err error)

ErrNotFound


付録


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

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


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