Skip to content

Commit 71ef4a2

Browse files
authored
add array filter with apply (#267)
1 parent d076e1b commit 71ef4a2

File tree

4 files changed

+58
-4
lines changed

4 files changed

+58
-4
lines changed

collection.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type Collection struct {
3838

3939
// Find find by condition filter,return QueryI
4040
func (c *Collection) Find(ctx context.Context, filter interface{}, opts ...opts.FindOptions) QueryI {
41+
4142
return &Query{
4243
ctx: ctx,
4344
collection: c.collection,

interface.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type CursorI interface {
5151
// QueryI Query interface
5252
type QueryI interface {
5353
Collation(collation *options.Collation) QueryI
54+
SetArrayFilters(*options.ArrayFilters) QueryI
5455
Sort(fields ...string) QueryI
5556
Select(selector interface{}) QueryI
5657
Skip(n int64) QueryI

query.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type Query struct {
3333
sort interface{}
3434
project interface{}
3535
hint interface{}
36+
arrayFilters *options.ArrayFilters
3637
limit *int64
3738
skip *int64
3839
batchSize *int64
@@ -89,6 +90,22 @@ func (q *Query) Sort(fields ...string) QueryI {
8990
return newQ
9091
}
9192

93+
// SetArrayFilter use for apply update array
94+
// For Example :
95+
// var res = QueryTestItem{}
96+
// change := Change{
97+
// Update: bson.M{"$set": bson.M{"instock.$[elem].qty": 100}},
98+
// ReturnNew: false,
99+
// }
100+
// cli.Find(context.Background(), bson.M{"name": "Lucas"}).
101+
// SetArrayFilters(&options.ArrayFilters{Filters: []interface{}{bson.M{"elem.warehouse": bson.M{"$in": []string{"C", "F"}}},}}).
102+
// Apply(change, &res)
103+
func (q *Query) SetArrayFilters(filter *options.ArrayFilters) QueryI {
104+
newQ := q
105+
newQ.arrayFilters = filter
106+
return newQ
107+
}
108+
92109
// Select is used to determine which fields are displayed or not displayed in the returned results
93110
// Format: bson.M{"age": 1} means that only the age field is displayed
94111
// bson.M{"age": 0} means to display other fields except age
@@ -405,6 +422,10 @@ func (q *Query) findOneAndUpdate(change Change, result interface{}) error {
405422
opts.SetReturnDocument(options.After)
406423
}
407424

425+
if q.arrayFilters != nil {
426+
opts.SetArrayFilters(*q.arrayFilters)
427+
}
428+
408429
err := q.collection.FindOneAndUpdate(q.ctx, q.filter, change.Update, opts).Decode(result)
409430
if change.Upsert && !change.ReturnNew && err == mongo.ErrNoDocuments {
410431
return nil

query_test.go

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,23 @@ import (
1919
"testing"
2020
"time"
2121

22+
"github.com/qiniu/qmgo/operator"
2223
"github.com/stretchr/testify/require"
2324
"go.mongodb.org/mongo-driver/bson"
2425
"go.mongodb.org/mongo-driver/bson/primitive"
2526
"go.mongodb.org/mongo-driver/mongo"
26-
27-
"github.com/qiniu/qmgo/operator"
27+
"go.mongodb.org/mongo-driver/mongo/options"
2828
)
2929

3030
type QueryTestItem struct {
3131
Id primitive.ObjectID `bson:"_id"`
3232
Name string `bson:"name"`
3333
Age int `bson:"age"`
34+
35+
Instock []struct {
36+
Warehouse string `bson:"warehouse"`
37+
Qty int `bson:"qty"`
38+
} `bson:"instock"`
3439
}
3540

3641
type QueryTestItem2 struct {
@@ -679,8 +684,13 @@ func TestQuery_Apply(t *testing.T) {
679684
docs := []interface{}{
680685
bson.M{"_id": id1, "name": "Alice", "age": 18},
681686
bson.M{"_id": id2, "name": "Alice", "age": 19},
682-
bson.M{"_id": id3, "name": "Lucas", "age": 20},
683-
}
687+
bson.M{"_id": id3, "name": "Lucas", "age": 20, "instock": []bson.M{
688+
{"warehouse": "B", "qty": 15},
689+
{"warehouse": "C", "qty": 35},
690+
{"warehouse": "E", "qty": 15},
691+
{"warehouse": "F", "qty": 45},
692+
}}}
693+
684694
_, _ = cli.InsertMany(context.Background(), docs)
685695

686696
var err error
@@ -829,6 +839,26 @@ func TestQuery_Apply(t *testing.T) {
829839
ast.NoError(err)
830840
ast.Equal("", res4.Name)
831841
ast.Equal(0, res4.Age)
842+
843+
var res5 = QueryTestItem{}
844+
filter5 := bson.M{"name": "Lucas"}
845+
change5 := Change{
846+
Update: bson.M{"$set": bson.M{"instock.$[elem].qty": 100}},
847+
ReturnNew: true,
848+
}
849+
err = cli.Find(context.Background(), filter5).SetArrayFilters(&options.ArrayFilters{Filters: []interface{}{
850+
bson.M{"elem.warehouse": bson.M{"$in": []string{"C", "F"}}},
851+
}}).Apply(change5, &res5)
852+
ast.NoError(err)
853+
854+
for _, item := range res5.Instock {
855+
switch item.Warehouse {
856+
case "C", "F":
857+
ast.Equal(100, item.Qty)
858+
case "B", "E":
859+
ast.Equal(15, item.Qty)
860+
}
861+
}
832862
}
833863

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

0 commit comments

Comments
 (0)