在这个例子中,我们要把多个文档放在另一个文档中。这在MongoDB中被称为 "嵌入式文档模型"。我们的例子使用 "tokens "集合。每个token文档将包含零个或多个 "权限 "文档在其中。
数据库内容
准备工作
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"
]
}
]
}