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.


Veritabanı içeriği


Hazırlık


db.createCollection("tokens")
db.tokens.createIndex({"uuid":1},{unique:true,name:"UQ_uuid"})

Token verileri


[
{
"_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
}
]

Depo


Modeller


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"`
}

Depolayıcı


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
}

Test


Ekleme


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)
}

Bulma


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"
]
}
]
}