16/03/2021 - GO, MONGODB
Bu örnekte, bir belgede birden çok "iç" belge tutacağız. Buna MongoDB'de "gömülü belge modeli" denir. Örneğimiz "token" koleksiyonunu kullanır. Her token belgesinde sıfır veya çok sayıda "permission" belgesi bulunur.
db.createCollection("tokens")
db.tokens.createIndex({"uuid":1},{unique:true,name:"UQ_uuid"})
[
{
"_id": {
"$oid": "6050986944799a96c0f7b1f4"
},
"uuid": "7d5e2a9f-b6b9-4356-af3c-be772b3cf821",
"type": "access token",
"permissions": [
{
"uuid": "f2222ef5-7f9b-46fa-a7e6-c88b4126e9fe",
"type": "accounts",
"actions": [
"read",
"write"
]
},
{
"uuid": "2cffcc36-0efc-4d09-bb0a-a36f2b6433be",
"type": "balances",
"actions": [
"read"
]
}
]
},
{
"_id": {
"$oid": "605098e921410aa61d2be92b"
},
"uuid": "38a934d7-73cf-4874-8af1-874d4c03335f",
"type": "refresh token",
"permissions": null
}
]
package storage
import "context"
type TokenStorer interface {
Insert(ctx context.Context, token Token) error
Find(ctx context.Context, uuid string) (Token, error)
}
type Token struct {
ID string `bson:"_id,omitempty"`
UUID string `bson:"uuid"`
Type string `bson:"type"`
Permissions []Permission `bson:"permissions"`
}
type Permission struct {
UUID string `bson:"uuid"`
Type string `bson:"type"`
Actions []string `bson:"actions"`
}
package mongodb
import (
"context"
"log"
"time"
"github.com/you/mongo/internal/pkg/domain"
"github.com/you/mongo/internal/pkg/storage"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
var _ storage.TokenStorer = TokenStorage{}
type TokenStorage struct {
Database *mongo.Database
Timeout time.Duration
}
func (t TokenStorage) Insert(ctx context.Context, token storage.Token) error {
ctx, cancel := context.WithTimeout(ctx, t.Timeout)
defer cancel()
if _, err := t.Database.Collection("tokens").InsertOne(ctx, token); err != nil {
log.Println(err)
if er, ok := err.(mongo.WriteException); ok && er.WriteErrors[0].Code == 11000 {
return domain.ErrConflict
}
return domain.ErrInternal
}
return nil
}
func (t TokenStorage) Find(ctx context.Context, uuid string) (storage.Token, error) {
ctx, cancel := context.WithTimeout(ctx, t.Timeout)
defer cancel()
var tok storage.Token
qry := bson.M{"uuid": uuid}
err := t.Database.Collection("tokens").FindOne(ctx, qry).Decode(&tok)
if err != nil {
log.Println(err)
if err == mongo.ErrNoDocuments {
return storage.Token{}, domain.ErrNotFound
}
return storage.Token{}, domain.ErrInternal
}
return tok, nil
}
storer := TokenStorage{Database: database, Timeout: time.Second * 5}
if err := storer.Insert(context.Background(), Token{
UUID: uuid.New().String(),
Type: "access token",
Permissions: []Permission{
{
UUID: uuid.New().String(),
Type: "accounts",
Actions: []string{"read", "write"},
},
{
UUID: uuid.New().String(),
Type: "balances",
Actions: []string{"read"},
},
},
}); err != nil {
log.Fatalln(err)
}
storer := TokenStorage{Database: database, Timeout: time.Second * 5}
token, err := storer.Find(context.Background(), "7d5e2a9f-b6b9-4356-af3c-be772b3cf821")
if err != nil {
log.Fatalln(err)
}
data, _ := json.MarshalIndent(token, "", " ")
log.Println(string(data))
{
"ID": "6050986944799a96c0f7b1f4",
"UUID": "7d5e2a9f-b6b9-4356-af3c-be772b3cf821",
"Type": "access token",
"Permissions": [
{
"UUID": "f2222ef5-7f9b-46fa-a7e6-c88b4126e9fe",
"Type": "accounts",
"Actions": [
"read",
"write"
]
},
{
"UUID": "2cffcc36-0efc-4d09-bb0a-a36f2b6433be",
"Type": "balances",
"Actions": [
"read"
]
}
]
}