$ go get go.mongodb.org/mongo-driver/mongo
$ go get go.mongodb.org/mongo-driver/mongo/options
$ go get go.mongodb.org/mongo-driver/bson
import (
"context"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
Mongo_URL := "mongodb://127.0.0.1:27017"
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(Mongo_URL))
//mongodb password가 설정되있는경우
credential := options.Credential{
Username: "codz",
Password: "states",
}
connect := func(dataSource string) (*mongo.Client, error) {
if client, err := mongo.Connect(context.Background(), options.Client().ApplyURI(dataSource).SetAuth(credential)); err != nil {
return nil, err
} else if err = client.Ping(context.Background(), nil); err != nil { //커넥션 유지를 위한 Ping
return nil, err
} else {
return client, nil
}
}
client, err := connect("mongodb://127.0.0.1:27017")
//db -> collection 단계적 접근
db := client.Database("go-ready") // database 접속
col := db.Collection("tPerson") // collection 접속
//collection으로 바로 접근
coll := client.Database("go-ready").Collection("tPerson")
//한 DB내 여러 collection 접근방식
db := client.Database("go-ready")
colPerson := db.Collection("tPerson")
colStudent := db.Collection("tStudent")
colWoman := db.Collection("tWoman")
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil {
panic(err)
}
defer func() {
if err = client.Disconnect(context.TODO()); err != nil { //연결해제
panic(err)
}
}()
func (coll *Collection) InsertOne(ctx context.Context, document interface{},
opts ...*options.InsertOneOptions) (*InsertOneResult, error)
res, err := coll.InsertOne(context.TODO(), bson.D{{"name", "Alice"}})
if err != nil {
log.Fatal(err)
}
func (coll *Collection) InsertMany(ctx context.Context, documents []interface{},
opts ...*options.InsertManyOptions) (*InsertManyResult, error)
docs := []interface{}{
bson.D{{"name", "Alice"}},
bson.D{{"name", "Bob"}},
}
// 삽입 시 정렬 여부
opts := options.InsertMany().SetOrdered(false)
// bson 형태의 객체 리스트 전달
res, err := coll.InsertMany(context.TODO(), docs, opts)
if err != nil {
log.Fatal(err)
}
func (coll *Collection) Find(ctx context.Context, filter interface{},
opts ...*options.FindOptions) (cur *Cursor, err error)
cursor, err := coll.Find(context.TODO(), bson.D{{"name", "Bob"}}, opts)
if err != nil {
log.Fatal(err)
}
// cursor에 반환된 모든 값을 가져와 result 값에 저장 후 출력한다.
var results []bson.M
if err = cursor.All(context.TODO(), &results); err != nil {
log.Fatal(err)
}
func (coll *Collection) FindOne(ctx context.Context, filter interface{},
opts ...*options.FindOneOptions) *SingleResult
// 검색한 데이터를 저장할 result 공간 할당
var result bson.M
// 정상적으로 데이터를 찾으면 result에 결과가 대입된다.
err := coll.FindOne(
context.TODO(),
bson.D{{"_id", id}}
).Decode(&result)
func (coll *Collection) UpdateOne(ctx context.Context, filter interface{}, update interface{},
opts ...*options.UpdateOptions) (*UpdateResult, error)
filter := bson.D{{"_id", id}}
update := bson.D{{"$set", bson.D{{"email", "newemail@example.com"}}}}
result, err := coll.UpdateOne(context.TODO(), filter, update, opts)
if err != nil {
log.Fatal(err)
}
func (coll *Collection) UpdateMany(ctx context.Context, filter interface{}, update interface{},
opts ...*options.UpdateOptions) (*UpdateResult, error)
today := time.Now().Format("01-01-1970")
// 생일이 today인 조건 생성
filter := bson.D{{"birthday", today}}
// 업데이트 내용 명시
update := bson.D{{"$inc", bson.D{{"age", 1}}}}
result, err := coll.UpdateMany(context.TODO(), filter, update)
if err != nil {
log.Fatal(err)
}
func (coll *Collection) DeleteOne(ctx context.Context, filter interface{},
opts ...*options.DeleteOptions) (*DeleteResult, error)
res, err := coll.DeleteOne(context.TODO(), bson.D{{"name", "bob"}})
if err != nil {
log.Fatal(err)
}
func (coll *Collection) DeleteMany(ctx context.Context, filter interface{},
opts ...*options.DeleteOptions) (*DeleteResult, error)
res, err := coll.DeleteMany(context.TODO(), bson.D{{"name", "bob"}})
if err != nil {
log.Fatal(err)
}
몽고DB는 bson(Binary Json)을 이용하고 있다.
작업을 지시할 때 작업 가능 시간, 작업 취소 등의 조건을 지시할 수 있는 작업 명세 역할
고루틴으로 작업 시작 시 일정시간 동안만 작업을 지시하거나 외부에서 작업을 취소할 때 사용
func Background() Context
func TODO() Context
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
package main
import (
"context"
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
wg.Add(1)
// 기본 context()를 생성해서 Cancel 기능을 입힌다 -> 취소 가능한 컨텍스트가 된다.
ctx, cancel := context.WithCancel(context.Background())
// 고루틴 함수 호출 (context)전달
go PrintEverySecond(ctx)
// 5초 딜레이
time.Sleep(5 * time.Second)
// context 생성 시 함께 만들어진 cancel() 함수 호출
// cancel() 함수 호출 시 Done() 함수로 끝났음을 시그널을 보낸다.
cancel()
wg.Wait()
}
func PrintEverySecond(ctx context.Context) {
// 1초당 채널로 알림
tick := time.Tick(time.Second)
// 무한 루프
for {
select {
// Done(): 작업이 끝날 때 채널이 나온다.
case <-ctx.Done():
wg.Done()
return
case <-tick:
fmt.Println("tick")
}
}
}
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val any) Context
해당 키값을 컨텍스트로 받아 반환하기
package main
import (
"context"
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
wg.Add(1)
// WithValue() : 작업을 지정할 때 특정데이터를 지시할 수 있다.
//number key에 9를 대입
ctx := context.WithValue(context.Background(), "number", 9)
go square(ctx)
wg.Wait()
}
func square(ctx context.Context) {
// ctx.Value() 함수를 이용해 지정된 데이터를 가져올 수 있다.
// v는 빈 인터페이스 타입
if v := ctx.Value("number"); v != nil {
// v는 빈인터페이스이므로 타입변환해서 출력할 수 있다.
n := v.(int)
fmt.Printf("Square:%d", n*n)
}
wg.Done()
}
ctx, cancel := context.WithCancel(context.Background())
ctx = context.WithValue(ctx, "number", 9)
ctx = context.WithValue(ctx, "keyword", "FDongFDong")
발행(Publisher)/구독자(Subscriber) 패턴 구현, 옵저버 패턴과 유사
package main
import (
"context"
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
ctx, cancel := context.WithCancel(context.Background())
wg.Add(4)
publisher := NewPublisher(ctx)
subscriber1 := NewSubscriber("AAA", ctx)
subscriber2 := NewSubscriber("BBB", ctx)
go publisher.Update()
subscriber1.Subscribe(publisher)
subscriber2.Subscribe(publisher)
go subscriber1.Update()
go subscriber2.Update()
go func() {
tick := time.Tick(time.Second * 2)
for {
select {
case <-tick:
publisher.Publish("Hello Message")
case <-ctx.Done():
wg.Done()
return
}
}
}()
fmt.Scanln()
cancel()
wg.Wait()
}
package main
import (
"context"
)
type Publisher struct {
ctx context.Context
// chan (chan<- string) : 채널에 채널을 넣는 타입
// chan<- string : 채널을 넣을 수만 있는 채널(일방향 채널)
// string <-chan : 데이터를 뺄 수만 있는 채널(일방향 채널)
// chan string : 양방향채널, 데이터를 넣고 뺼수 있는 채널(양방향 채널)
subscribeCh chan chan<- string
publishCh chan string
subscribers []chan<- string
}
// Publisher의 인스턴스를 만드는 함수
func NewPublisher(ctx context.Context) *Publisher {
return &Publisher{
ctx: ctx,
subscribeCh: make(chan chan<- string),
publishCh: make(chan string),
subscribers: make([]chan<- string, 0),
}
}
// 채널을 넣는다.
func (p *Publisher) Subscribe(sub chan<- string) {
p.subscribeCh <- sub
}
// 데이터를 뿌려주기위함
// publishCh 채널에 string 값을 넣는다.
func (p *Publisher) Publish(msg string) {
p.publishCh <- msg
}
func (p *Publisher) Update() {
for {
select {
// subscribeCh 채널에 데이터가 오면
case sub := <-p.subscribeCh:
// subscribers리스트에 추가한다.
p.subscribers = append(p.subscribers, sub)
// publishCh에서 데이터가 나오면
case msg := <-p.publishCh:
// subscriber들에게 데이터를 모두 전달해준다.
for _, subscriber := range p.subscribers {
subscriber <- msg
}
case <-p.ctx.Done():
wg.Done()
return
}
}
}
package main
import (
"context"
"fmt"
)
type Subscriber struct {
ctx context.Context
name string
msgCh chan string
}
func NewSubscriber(name string, ctx context.Context) *Subscriber {
return &Subscriber{
ctx: ctx,
name: name,
msgCh: make(chan string),
}
}
func (s *Subscriber) Subscribe(pub *Publisher) {
pub.Subscribe(s.msgCh)
}
func (s *Subscriber) Update() {
for {
select {
case msg := <-s.msgCh:
fmt.Printf("%s got Message:%s\n", s.name, msg)
case <-s.ctx.Done():
wg.Done()
return
}
}
}
> ./example01
AAA got Message:Hello Message
BBB got Message:Hello Message
BBB got Message:Hello Message
AAA got Message:Hello Message
BBB got Message:Hello Message
AAA got Message:Hello Message
BBB got Message:Hello Message
AAA got Message:Hello Message
BBB got Message:Hello Message
AAA got Message:Hello Message
eBBB got Message:Hello Message
AAA got Message:Hello Message
nd