Skip to content

Commit 82a7d52

Browse files
Merge pull request #24 from chenmingyong0423/feature/build
implements the lookup method for build the $lookup stage
2 parents 4abfe12 + 606b88d commit 82a7d52

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

builder/aggregation/aggregation_stage_builder.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,23 @@ func (b *StageBuilder) Count(countName string) *StageBuilder {
140140
return b
141141
}
142142

143+
func (b *StageBuilder) Lookup(from, as string, opt *LookUpOptions) *StageBuilder {
144+
d := bson.D{bson.E{Key: "from", Value: from}}
145+
if opt.LocalField != "" && opt.ForeignField != "" {
146+
d = append(d, bson.E{Key: "localField", Value: opt.LocalField})
147+
d = append(d, bson.E{Key: "foreignField", Value: opt.ForeignField})
148+
}
149+
if len(opt.Let) > 0 {
150+
d = append(d, bson.E{Key: "let", Value: opt.Let})
151+
}
152+
if len(opt.Pipeline) > 0 {
153+
d = append(d, bson.E{Key: "pipeline", Value: opt.Pipeline})
154+
}
155+
d = append(d, bson.E{Key: "as", Value: as})
156+
b.pipeline = append(b.pipeline, bson.D{bson.E{Key: StageLookUp, Value: d}})
157+
return b
158+
}
159+
143160
func (b *StageBuilder) Build() mongo.Pipeline {
144161
return b.pipeline
145162
}

builder/aggregation/aggregation_stage_builder_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,3 +654,77 @@ func TestStageBuilder_SortByCount(t *testing.T) {
654654
func TestStageBuilder_Count(t *testing.T) {
655655
assert.Equal(t, mongo.Pipeline{bson.D{bson.E{Key: "$count", Value: "passing_scores"}}}, StageBsonBuilder().Count("passing_scores").Build())
656656
}
657+
658+
func TestStageBuilder_Lookup(t *testing.T) {
659+
testCases := []struct {
660+
name string
661+
from string
662+
as string
663+
opt *LookUpOptions
664+
665+
want mongo.Pipeline
666+
}{
667+
{
668+
name: "basic",
669+
from: "orders",
670+
opt: &LookUpOptions{
671+
LocalField: "_id",
672+
ForeignField: "userId",
673+
Let: nil,
674+
Pipeline: nil,
675+
},
676+
as: "userOrders",
677+
want: mongo.Pipeline{
678+
{
679+
bson.E{Key: "$lookup", Value: bson.D{
680+
bson.E{Key: "from", Value: "orders"},
681+
bson.E{Key: "localField", Value: "_id"},
682+
bson.E{Key: "foreignField", Value: "userId"},
683+
bson.E{Key: "as", Value: "userOrders"},
684+
}},
685+
},
686+
},
687+
},
688+
{
689+
name: "advanced case",
690+
from: "orders",
691+
opt: &LookUpOptions{
692+
LocalField: "",
693+
ForeignField: "",
694+
Let: bson.D{bson.E{Key: "userId", Value: "$_id"}},
695+
Pipeline: mongo.Pipeline{
696+
{
697+
bson.E{Key: "$match", Value: bson.D{bson.E{Key: "$expr", Value: bson.D{bson.E{Key: "$and", Value: []any{
698+
bson.D{bson.E{Key: "$eq", Value: []any{"$userId", "$$userId"}}},
699+
bson.D{bson.E{Key: "$gt", Value: []any{"$totalAmount", 100}}},
700+
}}}}}},
701+
},
702+
},
703+
},
704+
as: "largeOrders",
705+
want: mongo.Pipeline{
706+
{
707+
bson.E{Key: "$lookup", Value: bson.D{
708+
bson.E{Key: "from", Value: "orders"},
709+
bson.E{Key: "let", Value: bson.D{bson.E{Key: "userId", Value: "$_id"}}},
710+
bson.E{Key: "pipeline", Value: mongo.Pipeline{
711+
{
712+
bson.E{Key: "$match", Value: bson.D{bson.E{Key: "$expr", Value: bson.D{bson.E{Key: "$and", Value: []any{
713+
bson.D{bson.E{Key: "$eq", Value: []any{"$userId", "$$userId"}}},
714+
bson.D{bson.E{Key: "$gt", Value: []any{"$totalAmount", 100}}},
715+
}}}}}},
716+
},
717+
}},
718+
bson.E{Key: "as", Value: "largeOrders"},
719+
},
720+
},
721+
},
722+
},
723+
},
724+
}
725+
for _, tc := range testCases {
726+
t.Run(tc.name, func(t *testing.T) {
727+
assert.Equal(t, tc.want, StageBsonBuilder().Lookup(tc.from, tc.as, tc.opt).Build())
728+
})
729+
}
730+
}

builder/aggregation/types.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2024 chenmingyong0423
2+
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package aggregation
16+
17+
import (
18+
"go.mongodb.org/mongo-driver/bson"
19+
"go.mongodb.org/mongo-driver/mongo"
20+
)
21+
22+
const (
23+
StageLookUp = "$lookup"
24+
)
25+
26+
type LookUpOptions struct {
27+
LocalField string
28+
ForeignField string
29+
Let bson.D
30+
Pipeline mongo.Pipeline
31+
}

0 commit comments

Comments
 (0)