| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 | package moimport (	"strings")type PipeCollection interface {	Pipeline() D}type Filter interface {	Done() D}// Grouper// Group 拥有 100MB 内存大小限制 https://www.mongodb.com/docs/v6.0/reference/operator/aggregation/group/#-group-and-memory-restrictionstype Grouper struct {	Filter D}func (g *Grouper) Add(k string, v any) *Grouper {	g.Filter = append(g.Filter, E{Key: k, Value: v})	return g}func (g *Grouper) Done() D {	return g.Filter}func (g *Grouper) Pipeline() D {	return D{{Key: PsGroup, Value: g.Filter}}}func (g *Grouper) UnmarshalJSON(v []byte) error {	return UnmarshalExtJSON(v, true, g.Pipeline())}func (g *Grouper) MarshalJSON() ([]byte, error) {	return MarshalExtJSON(g.Pipeline(), true, true)}// Matcher 匹配编译器// 注意: MongoDB 根据传入指令的顺序进行查询type Matcher struct {	Filter D}// Add 添加查询条件, 当已存在的方法不满足查询条件时, 可用此方法添加原始查询// db.inventory.find( { size: { h: 14, w: 21, uom: "cm" } } )func (m *Matcher) Add(k string, v any) *Matcher {	m.Filter = append(m.Filter, E{Key: k, Value: v})	return m}// Replace 替换已存在的条件func (m *Matcher) Replace(filter D) *Matcher {	m.Filter = filter	return m}// In 数组// db.inventory.find( { status: { $in: [ "A", "D" ] } } )func (m *Matcher) In(k string, v A) *Matcher {	m.Add(k, D{{Key: "$in", Value: v}})	return m}// Nin 数组反选// { field: { $nin: [ <value1>, <value2> ... <valueN> ] } }// // https://www.mongodb.com/docs/v6.0/reference/operator/query/nin/func (m *Matcher) Nin(k string, v A) *Matcher {	m.Add(k, D{{Key: "$nin", Value: v}})	return m}// Eq 相等func (m *Matcher) Eq(k string, v any) *Matcher {	m.Add(k, D{{Key: "$eq", Value: v}})	return m}// Ne 不相等// { field: { $ne: value } }// // https://www.mongodb.com/docs/v6.0/reference/operator/query/ne/func (m *Matcher) Ne(k string, v any) *Matcher {	m.Add(k, D{{Key: "$ne", Value: v}})	return m}// Gt 大于func (m *Matcher) Gt(k string, v any) *Matcher {	m.Add(k, D{{Key: "$gt", Value: v}})	return m}// Gte 大于等于func (m *Matcher) Gte(k string, v any) *Matcher {	m.Add(k, D{{Key: "$gte", Value: v}})	return m}// Lt 小于// Lt db.inventory.find( { status: "A", qty: { $lt: 30 } } )func (m *Matcher) Lt(k string, v any) *Matcher {	m.Add(k, D{{Key: "$lt", Value: v}})	return m}// Lte 小于等于func (m *Matcher) Lte(k string, v any) *Matcher {	m.Add(k, D{{Key: "$lte", Value: v}})	return m}// All 等效于 And 对指定值的操作;即以下声明:// { tags: { $all: [ "ssl" , "security" ] } }// { $and: [ { tags: "ssl" }, { tags: "security" } ] }func (m *Matcher) All(k string, v A) *Matcher {	m.Add(k, D{{Key: "$all", Value: v}})	return m}// Regex 正则表达式 https://www.mongodb.com/docs/v6.0/reference/operator/query/regex/// db.products.find( { description: { $regex: /^S/, $options: 'm' } } )// opt 为操作符:// i 区分大小写// m https://www.mongodb.com/docs/v6.0/reference/operator/query/regex/#multiline-match-for-lines-starting-with-specified-pattern// x// s 允许匹配点 (.) 字符// 操作符可以连用// 正则表达式操作符 https://www.mongodb.com/docs/v6.0/reference/operator/query/regex/#mongodb-query-op.-optionsfunc (m *Matcher) Regex(k string, v any, opt ...string) *Matcher {	val := D{{Key: "$regex", Value: v}}	if len(opt) > 0 {		val = append(val, E{Key: "$options", Value: strings.Join(opt, "")})	}	m.Add(k, val)	return m}// Not 等于 Regex 正则表达式的反选// db.inventory.find( { price: { $not: { $gt: 1.99 } } } )// db.inventory.find( { item: { $not: /^p.*/ } } )// db.inventory.find( { item: { $not: { $regex: "^p.*" } } } )// TODO Not 指令似乎仅支持一个 Key/Val, 待验证func (m *Matcher) Not(k string, v any) *Matcher {	m.Add(k, D{{Key: "$not", Value: v}})	return m}// Or 或者// db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )// https://www.mongodb.com/docs/v6.0/reference/operator/query/or/func (m *Matcher) Or(v *Matcher) *Matcher {	m.Add("$or", m.toSlice(v))	return m}// And 所有条件相等时// { $and: [ { tags: "ssl" }, { tags: "security" } ] }// https://www.mongodb.com/docs/v6.0/reference/operator/query/and/func (m *Matcher) And(v *Matcher) *Matcher {	m.Add("$and", m.toSlice(v))	return m}// Nor// db.inventory.find( { $nor: [ { price: 1.99 }, { sale: true } ]  } )// db.inventory.find( { $nor: [ { price: 1.99 }, { price: { $exists: false } }, { sale: true }, { sale: { $exists: false } } ] } )// https://www.mongodb.com/docs/v6.0/reference/operator/query/nor/func (m *Matcher) Nor(v *Matcher) *Matcher {	m.Add("$nor", m.toSlice(v))	return m}// ElemMatch 数组元素查找, elemMatch 会匹配数组内的所有元素// 数字类型: db.scores.find( { results: { $elemMatch: { $gte: 80, $lt: 85 } } } )// Object 类型:// db.survey.find( { results: { $elemMatch: { product: "xyz", score: { $gte: 8 } } } } )// db.survey.find( { results: { $elemMatch: { product: "xyz" } } } )// https://www.mongodb.com/docs/manual/reference/operator/query/elemMatch/func (m *Matcher) ElemMatch(field string, v *Matcher) *Matcher {	for i, ele := range m.Filter {		if ele.Key == field {			m.Filter[i] = E{Key: "$elemMatch", Value: append(ele.Value.(D), v.Done()...)}			return m		}	}	m.Add(field, D{{Key: "$elemMatch", Value: v.Done()}})	return m}func (m *Matcher) toSlice(v *Matcher) A {	filter := v.Done()	builder := make(A, len(filter))	for i, e := range filter {		builder[i] = D{e}	}	return builder}func (m *Matcher) Done() D {	return m.Filter}func (m *Matcher) Pipeline() D {	return D{{Key: PsMatch, Value: m.Filter}}}func (m *Matcher) UnmarshalJSON(v []byte) error {	return UnmarshalExtJSON(v, true, m.Pipeline())}func (m *Matcher) MarshalJSON() ([]byte, error) {	return MarshalExtJSON(m.Pipeline(), true, true)}// Projecter 控制返回的字段type Projecter struct {	Filter D}// AddEnable Value 为非 0 的数时表示返回此字段func (p *Projecter) AddEnable(k string) *Projecter {	p.Filter = append(p.Filter, E{Key: k, Value: 1})	return p}// AddDisable Value 为 0 时表示不返回此字段func (p *Projecter) AddDisable(k string) *Projecter {	p.Filter = append(p.Filter, E{Key: k, Value: 0})	return p}func (p *Projecter) Done() D {	return p.Filter}func (p *Projecter) Pipeline() D {	return D{{Key: PsProject, Value: p.Filter}}}func (p *Projecter) UnmarshalJSON(v []byte) error {	return UnmarshalExtJSON(v, true, p.Pipeline())}func (p *Projecter) MarshalJSON() ([]byte, error) {	return MarshalExtJSON(p.Pipeline(), true, true)}// Sorter// Sort 根据字段对文档排序, 最多可以指定 32 个字段 https://www.mongodb.com/docs/v6.0/reference/operator/aggregation/sort/type Sorter struct {	Filter D}func (s *Sorter) AddASC(k string) *Sorter {	s.Filter = append(s.Filter, E{Key: k, Value: int64(1)})	return s}func (s *Sorter) AddDESC(k string) *Sorter {	s.Filter = append(s.Filter, E{Key: k, Value: int64(-1)})	return s}func (s *Sorter) Done() D {	return s.Filter}func (s *Sorter) Pipeline() D {	return D{{Key: PsSort, Value: s.Filter}}}func (s *Sorter) UnmarshalJSON(v []byte) error {	return UnmarshalExtJSON(v, true, s.Pipeline())}func (s *Sorter) MarshalJSON() ([]byte, error) {	return MarshalExtJSON(s.Pipeline(), true, true)}type Limiter struct {	Limit int64}func (l *Limiter) Pipeline() D {	return D{{Key: PsLimit, Value: l.Limit}}}func (l *Limiter) UnmarshalJSON(v []byte) error {	return UnmarshalExtJSON(v, true, l.Pipeline())}func (l *Limiter) MarshalJSON() ([]byte, error) {	return MarshalExtJSON(l.Pipeline(), true, true)}func NewLimiter(limit int64) *Limiter {	return &Limiter{Limit: limit}}type Skipper struct {	Skip int64}func (s *Skipper) Pipeline() D {	return D{{Key: PsSkip, Value: s.Skip}}}func (s *Skipper) UnmarshalJSON(v []byte) error {	return UnmarshalExtJSON(v, true, s.Pipeline())}func (s *Skipper) MarshalJSON() ([]byte, error) {	return MarshalExtJSON(s.Pipeline(), true, true)}func NewSkip(skip int64) *Skipper {	return &Skipper{Skip: skip}}type Looker struct {	From         string	LocalField   string	ForeignField string	Let          D	Pipe         Pipeline	As           string}func (l *Looker) SetFrom(from string) *Looker {	l.From = from	return l}func (l *Looker) SetLocalField(field string) *Looker {	l.LocalField = field	return l}func (l *Looker) SetForeignField(filed string) *Looker {	l.ForeignField = filed	return l}func (l *Looker) SetLet(let D) *Looker {	l.Let = let	return l}func (l *Looker) SetPipe(pipe Pipeline) *Looker {	l.Pipe = pipe	return l}func (l *Looker) SetAs(as string) *Looker {	l.As = as	return l}func (l *Looker) Pipeline() D {	m := D{}	if l.From != "" {		m = append(m, E{Key: "from", Value: l.From})	}	if l.LocalField != "" {		m = append(m, E{Key: "localField", Value: l.LocalField})	}	if l.ForeignField != "" {		m = append(m, E{Key: "foreignField", Value: l.ForeignField})	}	if len(l.Let) > 0 {		m = append(m, E{Key: "let", Value: l.Let})	}	if len(l.Pipe) > 0 {		m = append(m, E{Key: "pipeline", Value: l.Pipe})	}	if l.As != "" {		m = append(m, E{Key: "as", Value: l.As})	}	return D{{Key: PsLookup, Value: m}}}func (l *Looker) UnmarshalJSON(v []byte) error {	return UnmarshalExtJSON(v, true, l.Pipeline())}func (l *Looker) MarshalJSON() ([]byte, error) {	return MarshalExtJSON(l.Pipeline(), true, true)}// Setter 使用 $addField/$set 为查询的结果新增字段, 其中 $set 为 $addField 的别名// 添加的 值 可使用管道表达式 https://www.mongodb.com/docs/manual/meta/aggregation-quick-reference/#std-label-aggregation-expressionstype Setter struct {	Filter D}func (s *Setter) Add(field string, filter D) {	s.Filter = append(s.Filter, E{Key: field, Value: filter})}// SUM 合计字段的值, 当字段重复出现时则会重复计算// 联合 $add 运算符一起使用func (s *Setter) SUM(fieldName string, field []string) {	for i := 0; i < len(field); i++ {		if strings.HasPrefix(field[i], "$") {			continue		}		field[i] = "$" + field[i]	}	s.Add(fieldName, D{{Key: PoSum, Value: D{{Key: PoAdd, Value: field}}}})}func (s *Setter) Pipeline() D {	return D{{Key: PsSet, Value: s.Filter}}}type Piper struct {	pipe Pipeline}func (p *Piper) Match(matcher PipeCollection) {	p.pipe = append(p.pipe, matcher.Pipeline())}func (p *Piper) Lookup(looker PipeCollection) {	p.pipe = append(p.pipe, looker.Pipeline())}// Documents 搜索文档// https://www.mongodb.com/docs/v6.0/reference/operator/aggregation/documents/#examplesfunc (p *Piper) Documents(d D) {	p.pipe = append(p.pipe, D{{Key: PsDocuments, Value: d}})}func (p *Piper) Pipeline() Pipeline {	return p.pipe}type Updater struct {	Setter    D	UnSetter  D	Pusher    D	Puller    D	PullerAll D	CurDate   D}// Set 将 k 字段的内容更新为 v// Set 不适用于更新数据类型为 TypeArray 的字段, 请使用 Push 或 Pull 系列方法// https://www.mongodb.com/docs/manual/reference/operator/update/set/func (o *Updater) Set(k string, v any) {	o.Setter = append(o.Setter, E{Key: k, Value: v})}// Unset 从文档中删除此字段// https://www.mongodb.com/docs/manual/reference/operator/update/unset/func (o *Updater) Unset(k string) {	o.UnSetter = append(o.UnSetter, E{Key: k, Value: nil})}// Push 将 v 添加到数组的最后面// https://www.mongodb.com/docs/manual/reference/operator/update/push/func (o *Updater) Push(k string, v any) {	o.Pusher = append(o.Pusher, E{Key: k, Value: v})}// PushEach 将 v 的展开并添加到数组的后面// https://www.mongodb.com/docs/manual/reference/operator/update/each/func (o *Updater) PushEach(k string, v A) {	o.Pusher = append(o.Pusher, E{Key: k, Value: D{{Key: "$each", Value: v}}})}// Pull 删除数组内的元素 v// https://www.mongodb.com/docs/manual/reference/operator/update/pull/func (o *Updater) Pull(k string, v any) {	o.Puller = append(o.Puller, E{Key: k, Value: v})}// PullAll 删除数组内包含 v 数组内的所有元素// https://www.mongodb.com/docs/manual/reference/operator/update/pullAll/func (o *Updater) PullAll(k string, v A) {	o.PullerAll = append(o.PullerAll, E{Key: k, Value: v})}func (o *Updater) SetCurrentDate(k string, v bool) {	o.CurDate = append(o.CurDate, E{Key: k, Value: v})}func (o *Updater) Done() D {	op := D{}	if len(o.CurDate) > 0 {		op = append(op, E{Key: PoCurrentDate, Value: o.CurDate})	}	if len(o.Setter) > 0 {		op = append(op, E{Key: PoSet, Value: o.Setter})	}	if len(o.UnSetter) > 0 {		op = append(op, E{Key: PoUnset, Value: o.UnSetter})	}	if len(o.Pusher) > 0 {		op = append(op, E{Key: PoPush, Value: o.Pusher})	}	if len(o.Puller) > 0 {		op = append(op, E{Key: PoPull, Value: o.Puller})	}	if len(o.PullerAll) > 0 {		op = append(op, E{Key: PoPullAll, Value: o.PullerAll})	}	return op}// NewPipeline 管道聚合// 请注意 pipe 顺序func NewPipeline(pipe ...PipeCollection) Pipeline {	p := make(Pipeline, len(pipe))	for i := 0; i < len(pipe); i++ {		p[i] = pipe[i].Pipeline()	}	return p}
 |