Skip to content

Commit

Permalink
update aggregate
Browse files Browse the repository at this point in the history
  • Loading branch information
phuong committed Jun 13, 2022
1 parent 8d3dd1f commit 4379029
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 66 deletions.
84 changes: 52 additions & 32 deletions internal/mopertest/aggregation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,75 @@ package mopertest

import (
"context"
"encoding/json"
"fmt"
"testing"

"github.com/func25/mongofunc/mocom"
"github.com/func25/mongofunc/moper"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)

func TestAggregationTest(t *testing.T) {
matchStage := bson.D{
{
Key: "$match",
Value: moper.D{}.InEll("damage", 1, 2, 3, 4, 5, 6, 7, 8, 9),
},
func TestAggregation(t *testing.T) {
intArr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}

matchStage := moper.D{}.MatchD(moper.D{}.InArray("damage", intArr))
groupStage := moper.D{}.Group(
moper.P{K: "_id", V: nil},
moper.P{K: "total", V: moper.D{}.Sum("damage")},
)

req := &mocom.AggregationRequest[Hero]{
Pipeline: []moper.D{matchStage, groupStage},
Options: []*options.AggregateOptions{},
}
result, err := mocom.Aggregate(context.Background(), req)
if err != nil {
t.Error(err)
return
}

groupStage := bson.D{
{
Key: "$group",
Value: bson.D{
{
Key: "_id",
Value: nil,
},
{
Key: "total",
Value: bson.D{
{
Key: "$sum",
Value: "$damage",
},
},
},
},
},
expect := 0
for _, v := range intArr {
expect += v * v
}

if int(result[0]["total"].(int32)) != expect {
t.Error("wrong result", result[0]["total"], expect)
}
}

func TestLookup(t *testing.T) {
intArr := []int{1}
matchStage := moper.D{}.MatchD(moper.D{}.InArray("damage", intArr))

lookupStage := moper.D{}.LookUp().
From(Weapon{}.CollName()).
LocalField("damage").
ForeignField("damage").
As("weapon")

unwindStage := moper.D{}.Equal("$unwind", moper.D{}.Equal("path", "$weapon").Equal("preserveNullAndEmptyArrays", false))

req := &mocom.AggregationRequest[Hero]{
Pipeline: mongo.Pipeline{matchStage, groupStage},
Pipeline: []moper.D{matchStage, lookupStage.D(), unwindStage},
Options: []*options.AggregateOptions{},
Result: []primitive.M{},
}
if err := mocom.Aggregate(context.Background(), req); err != nil {
result, err := mocom.Aggregate(context.Background(), req)
if err != nil {
t.Error(err)
return
}

fmt.Println(req.Result)
x, err := json.Marshal(result)
fmt.Println(string(x))

// expect := 0
// for _, v := range intArr {
// expect += v * v
// }

// if result[0]["total"] != expect {
// t.Error("wrong result", result[0]["total"], expect)
// }
}
1 change: 0 additions & 1 deletion internal/mopertest/element_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

func TestExists(t *testing.T) {
ctx := context.Background()

filter := moper.D{}.Exists("omit", true)
if count, err := mocom.Count[Hero](ctx, filter); err != nil {
t.Error("[TestExists]", err)
Expand Down
40 changes: 32 additions & 8 deletions internal/mopertest/seed.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,28 @@ import (
"strconv"

"github.com/func25/mongofunc/mocom"
"go.mongodb.org/mongo-driver/bson/primitive"
)

type Hero struct {
mocom.ID[primitive.ObjectID] `bson:",inline"`
Name string `bson:"name"`
Damage int `bson:"damage"`
SkillIds []int `bson:"skillIds"`
Omit bool `bson:"omit,omitempty"`
// weapon
type Weapon struct {
mocom.ID `bson:",inline"`
Type int `json:"type" bson:"type"`
Damage int `json:"damage" bson:"damage"`
}

func (Weapon) CollName() string {
return "Weapons"
}

const COLLECTION_NAME = "Heroes"
// hero
type Hero struct {
mocom.ID `bson:",inline"`
WeaponID interface{} `bson:"weaponId"`
Name string `bson:"name"`
Damage int `bson:"damage"`
SkillIds []int `bson:"skillIds"`
Omit bool `bson:"omit,omitempty"`
}

var (
ROUND = 10
Expand Down Expand Up @@ -50,6 +60,18 @@ func init() {
//Seed create 1 hero has 1 damage, 2 heroes have 2 damages,... until n (n == 10)
func Seed(ctx context.Context, n int) error {
count := 0
weapons := []*Weapon{}
for i := 0; i < 3; i++ {
x := &Weapon{
Type: i,
Damage: 1,
}
err := mocom.CreateWithID(ctx, x)
if err != nil {
return err
}
weapons = append(weapons, x)
}

for i := 0; i < n; i++ {
for j := 0; j <= i; j, count = j+1, count+1 {
Expand All @@ -58,6 +80,7 @@ func Seed(ctx context.Context, n int) error {
Damage: i + 1,
SkillIds: []int{1, 2, 3, 4, 5},
Omit: j == i,
WeaponID: weapons[j%3].ID.ID,
})
if err != nil {
return err
Expand All @@ -70,5 +93,6 @@ func Seed(ctx context.Context, n int) error {

func Clear(ctx context.Context) error {
_, err := mocom.Flush[Hero](ctx)
_, err = mocom.Flush[Weapon](ctx)
return err
}
14 changes: 12 additions & 2 deletions mocom/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,21 @@ import (
"go.mongodb.org/mongo-driver/mongo/options"
)

func Create[T MongoModel](ctx context.Context, model *T, opts ...*options.InsertOneOptions) (interface{}, error) {
col := collWrite((*model).CollName())
func Create[T Model](ctx context.Context, model T, opts ...*options.InsertOneOptions) (interface{}, error) {
col := collWrite(model.CollName())
if result, err := col.InsertOne(ctx, model, opts...); err != nil {
return nil, err
} else {
return result.InsertedID, nil
}
}

func CreateWithID[T IDModel](ctx context.Context, model T, opts ...*options.InsertOneOptions) error {
col := collWrite(model.CollName())
if result, err := col.InsertOne(ctx, model, opts...); err != nil {
return err
} else {
model.SetID(result.InsertedID)
return nil
}
}
4 changes: 2 additions & 2 deletions mocom/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"go.mongodb.org/mongo-driver/mongo/options"
)

func Find[T MongoModel](ctx context.Context, filter interface{}, opts ...*options.FindOptions) (res []T, err error) {
func Find[T Model](ctx context.Context, filter interface{}, opts ...*options.FindOptions) (res []T, err error) {
var t T
cur, err := collRead(t.CollName()).Find(ctx, filter, opts...)
if err != nil {
Expand All @@ -17,7 +17,7 @@ func Find[T MongoModel](ctx context.Context, filter interface{}, opts ...*option
return res, err
}

func FindOne[T MongoModel](ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (res *T, err error) {
func FindOne[T Model](ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (res *T, err error) {
res = new(T)
cur := collRead((*res).CollName()).FindOne(ctx, filter, opts...)
err = cur.Decode(&res)
Expand Down
25 changes: 14 additions & 11 deletions mocom/mocom.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,39 @@ import (
"time"

"github.com/func25/mongofunc/moper"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readconcern"
"go.mongodb.org/mongo-driver/mongo/readpref"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
)

func Count[T MongoModel](ctx context.Context, filter interface{}, opts ...*options.CountOptions) (int64, error) {
func Count[T Model](ctx context.Context, filter interface{}, opts ...*options.CountOptions) (int64, error) {
var t T
return collRead(t.CollName()).CountDocuments(ctx, filter, opts...)
}

func EstimatedCount[T MongoModel](ctx context.Context, opts ...*options.EstimatedDocumentCountOptions) (int64, error) {
func EstimatedCount[T Model](ctx context.Context, opts ...*options.EstimatedDocumentCountOptions) (int64, error) {
var t T
return collRead(t.CollName()).EstimatedDocumentCount(ctx, opts...)
}

func Aggregate[T MongoModel](ctx context.Context, req *AggregationRequest[T]) error {
func Aggregate[T Model](ctx context.Context, req *AggregationRequest[T]) (res []bson.M, err error) {
var t T
col := db.Collection(t.CollName())

cursor, err := col.Aggregate(ctx, req.Pipeline, req.Options...)
if err != nil {
return err
return nil, err
}
// fmt.Println(cursor)

err = cursor.All(ctx, &req.Result)
err = cursor.All(ctx, &res)

return err
return res, err
}

//Flush clears all records of collection and return number of deleted records
func Flush[T MongoModel](ctx context.Context) (int64, error) {
func Flush[T Model](ctx context.Context) (int64, error) {
var t T
result, err := db.Collection(t.CollName()).DeleteMany(ctx, moper.D{})
if err != nil {
Expand All @@ -63,14 +63,17 @@ func Tx(ctx context.Context, cfg TransactionConfig) (interface{}, error) {
return session.WithTransaction(ctx, cfg.Func, cfg.Options)
}

// TxOptimal will do the transaction with majority write-concern and local read-concern, client default read pref
// TxOptimal will do the transaction with majority write-concern
// snapshot read-concern, primary read preference
//
// This should be used when transaction does not contain any read
func TxOptimal(ctx context.Context, f func(ctx mongo.SessionContext) (interface{}, error)) (interface{}, error) {
if client == nil {
return nil, errors.New("client is nil, please using mocom to create connection to mongo server or using your own client connection")
}

wc := writeconcern.New(writeconcern.WMajority(), writeconcern.WTimeout(5*time.Second))
opts := options.Transaction().SetReadConcern(readconcern.Local()).SetWriteConcern(wc)
opts := options.Transaction().SetReadConcern(readconcern.Snapshot()).SetWriteConcern(wc).SetReadPreference(readpref.Primary())

session, err := client.StartSession()
if err != nil {
Expand Down
22 changes: 15 additions & 7 deletions mocom/model.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
package mocom

import (
"go.mongodb.org/mongo-driver/bson"
"github.com/func25/mongofunc/moper"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)

type MongoModel interface {
type Model interface {
CollName() string
}

type ID[T any] struct {
ID T `json:"id" bson:"_id,omitempty"`
type IDModel interface {
Model
SetID(t interface{})
}

type AggregationRequest[T MongoModel] struct {
Result []bson.M
Pipeline mongo.Pipeline
type ID struct {
ID interface{} `json:"id" bson:"_id,omitempty"`
}

func (id *ID) SetID(t interface{}) {
id.ID = t
}

type AggregationRequest[T Model] struct {
Pipeline []moper.D
Options []*options.AggregateOptions
}

Expand Down
6 changes: 3 additions & 3 deletions mocom/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import (
"go.mongodb.org/mongo-driver/mongo/options"
)

func UpdateOne[T MongoModel](ctx context.Context, filter interface{}, update interface{}, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error) {
func UpdateOne[T Model](ctx context.Context, filter interface{}, update interface{}, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error) {
var t T
return collWrite(t.CollName()).UpdateOne(ctx, filter, update, opts...)
}

func UpdateAndReturn[T MongoModel](ctx context.Context, filter interface{}, update interface{}, opts ...*options.FindOneAndUpdateOptions) (ptrT *T, err error) {
func UpdateAndReturn[T Model](ctx context.Context, filter interface{}, update interface{}, opts ...*options.FindOneAndUpdateOptions) (ptrT *T, err error) {
ptrT = new(T)
res := collWrite((*ptrT).CollName()).FindOneAndUpdate(ctx, filter, update, opts...)

Expand All @@ -24,7 +24,7 @@ func UpdateAndReturn[T MongoModel](ctx context.Context, filter interface{}, upda
return
}

func UpdateMany[T MongoModel](ctx context.Context, filter interface{}, update interface{}) (*mongo.UpdateResult, error) {
func UpdateMany[T Model](ctx context.Context, filter interface{}, update interface{}) (*mongo.UpdateResult, error) {
var t T
return collWrite(t.CollName()).UpdateMany(ctx, filter, update)
}
21 changes: 21 additions & 0 deletions moper/aggregate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package moper

func (d D) Match(pairs ...P) D {
return d.Equal("$match", toPair(pairs))
}

func (d D) MatchD(pair D) D {
return d.Equal("$match", pair)
}

func (d D) Group(pairs ...P) D {
return d.Equal("$group", toPair(pairs))
}

func (d D) GroupD(pair D) D {
return d.Equal("$group", pair)
}

func (d D) Sum(fieldName string) D {
return d.Equal("$sum", "$"+fieldName)
}
Loading

0 comments on commit 4379029

Please sign in to comment.