Skip to content

Commit

Permalink
add array filter with apply (#267)
Browse files Browse the repository at this point in the history
  • Loading branch information
xsean2020 authored Jan 20, 2023
1 parent d076e1b commit 71ef4a2
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 4 deletions.
1 change: 1 addition & 0 deletions collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type Collection struct {

// Find find by condition filter,return QueryI
func (c *Collection) Find(ctx context.Context, filter interface{}, opts ...opts.FindOptions) QueryI {

return &Query{
ctx: ctx,
collection: c.collection,
Expand Down
1 change: 1 addition & 0 deletions interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type CursorI interface {
// QueryI Query interface
type QueryI interface {
Collation(collation *options.Collation) QueryI
SetArrayFilters(*options.ArrayFilters) QueryI
Sort(fields ...string) QueryI
Select(selector interface{}) QueryI
Skip(n int64) QueryI
Expand Down
21 changes: 21 additions & 0 deletions query.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type Query struct {
sort interface{}
project interface{}
hint interface{}
arrayFilters *options.ArrayFilters
limit *int64
skip *int64
batchSize *int64
Expand Down Expand Up @@ -89,6 +90,22 @@ func (q *Query) Sort(fields ...string) QueryI {
return newQ
}

// SetArrayFilter use for apply update array
// For Example :
// var res = QueryTestItem{}
// change := Change{
// Update: bson.M{"$set": bson.M{"instock.$[elem].qty": 100}},
// ReturnNew: false,
// }
// cli.Find(context.Background(), bson.M{"name": "Lucas"}).
// SetArrayFilters(&options.ArrayFilters{Filters: []interface{}{bson.M{"elem.warehouse": bson.M{"$in": []string{"C", "F"}}},}}).
// Apply(change, &res)
func (q *Query) SetArrayFilters(filter *options.ArrayFilters) QueryI {
newQ := q
newQ.arrayFilters = filter
return newQ
}

// Select is used to determine which fields are displayed or not displayed in the returned results
// Format: bson.M{"age": 1} means that only the age field is displayed
// bson.M{"age": 0} means to display other fields except age
Expand Down Expand Up @@ -405,6 +422,10 @@ func (q *Query) findOneAndUpdate(change Change, result interface{}) error {
opts.SetReturnDocument(options.After)
}

if q.arrayFilters != nil {
opts.SetArrayFilters(*q.arrayFilters)
}

err := q.collection.FindOneAndUpdate(q.ctx, q.filter, change.Update, opts).Decode(result)
if change.Upsert && !change.ReturnNew && err == mongo.ErrNoDocuments {
return nil
Expand Down
39 changes: 35 additions & 4 deletions query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,23 @@ import (
"testing"
"time"

"github.com/qiniu/qmgo/operator"
"github.com/stretchr/testify/require"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"

"github.com/qiniu/qmgo/operator"
"go.mongodb.org/mongo-driver/mongo/options"
)

type QueryTestItem struct {
Id primitive.ObjectID `bson:"_id"`
Name string `bson:"name"`
Age int `bson:"age"`

Instock []struct {
Warehouse string `bson:"warehouse"`
Qty int `bson:"qty"`
} `bson:"instock"`
}

type QueryTestItem2 struct {
Expand Down Expand Up @@ -679,8 +684,13 @@ func TestQuery_Apply(t *testing.T) {
docs := []interface{}{
bson.M{"_id": id1, "name": "Alice", "age": 18},
bson.M{"_id": id2, "name": "Alice", "age": 19},
bson.M{"_id": id3, "name": "Lucas", "age": 20},
}
bson.M{"_id": id3, "name": "Lucas", "age": 20, "instock": []bson.M{
{"warehouse": "B", "qty": 15},
{"warehouse": "C", "qty": 35},
{"warehouse": "E", "qty": 15},
{"warehouse": "F", "qty": 45},
}}}

_, _ = cli.InsertMany(context.Background(), docs)

var err error
Expand Down Expand Up @@ -829,6 +839,26 @@ func TestQuery_Apply(t *testing.T) {
ast.NoError(err)
ast.Equal("", res4.Name)
ast.Equal(0, res4.Age)

var res5 = QueryTestItem{}
filter5 := bson.M{"name": "Lucas"}
change5 := Change{
Update: bson.M{"$set": bson.M{"instock.$[elem].qty": 100}},
ReturnNew: true,
}
err = cli.Find(context.Background(), filter5).SetArrayFilters(&options.ArrayFilters{Filters: []interface{}{
bson.M{"elem.warehouse": bson.M{"$in": []string{"C", "F"}}},
}}).Apply(change5, &res5)
ast.NoError(err)

for _, item := range res5.Instock {
switch item.Warehouse {
case "C", "F":
ast.Equal(100, item.Qty)
case "B", "E":
ast.Equal(15, item.Qty)
}
}
}

func TestQuery_BatchSize(t *testing.T) {
Expand All @@ -854,4 +884,5 @@ func TestQuery_BatchSize(t *testing.T) {
err := cli.Find(context.Background(), bson.M{"name": "Alice"}).BatchSize(1).All(&res)
ast.NoError(err)
ast.Len(res, 2)

}

0 comments on commit 71ef4a2

Please sign in to comment.