在这个例子中,我们要把一个文档放在另一个文档中。这在MongoDB中被称为 "嵌入式文档模型"。我们的例子使用 "tokens "集合。每个token文档将包含零或一个 "权限 "文档。
数据库内容
准备工作
db.createCollection("tokens")
db.tokens.createIndex({"uuid":1},{unique:true,name:"UQ_uuid"})
令牌数据
[
{
"_id": {
"$oid": "6050b16571b3921d9c825d66"
},
"uuid": "2f249152-6f8f-4873-81ef-ae6d7de0b582",
"type": "access token",
"permission": {
"uuid": "33e5140b-80ac-42ff-b6aa-59e1f855847a",
"type": "accounts",
"actions": [
"read",
"write"
]
}
},
{
"_id": {
"$oid": "6050b16571b3921d9c825d67"
},
"uuid": "e2513685-bfed-4962-a897-230eb149fbac",
"type": "refresh token",
"permission": {
}
}
]
存储
模型
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"`
Permission Permission `bson:"permission"`
}
type Permission struct {
UUID string `bson:"uuid,omitempty"`
Type string `bson:"type,omitempty"`
Actions []string `bson:"actions,omitempty"`
}
存储器
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",
Permission: Permission{
UUID: uuid.New().String(),
Type: "accounts",
Actions: []string{"read", "write"},
},
}); err != nil {
log.Fatalln(err)
}
查找
storer := TokenStorage{Database: database, Timeout: time.Second * 5}
token, err := storer.Find(context.Background(), "2f249152-6f8f-4873-81ef-ae6d7de0b582")
if err != nil {
log.Fatalln(err)
}
data, _ := json.MarshalIndent(token, "", " ")
log.Println(string(data))
{
"ID": "6050b16571b3921d9c825d66",
"UUID": "2f249152-6f8f-4873-81ef-ae6d7de0b582",
"Type": "access token",
"Permission": {
"UUID": "33e5140b-80ac-42ff-b6aa-59e1f855847a",
"Type": "accounts",
"Actions": [
"read",
"write"
]
}
}