forked from qiniu/qmgo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcollection.go
222 lines (185 loc) · 6.67 KB
/
collection.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
package qmgo
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"strings"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/x/bsonx"
)
// Collection is a handle to a MongoDB collection
type Collection struct {
collection *mongo.Collection
}
// Find find by condition filter,return QueryI
func (c *Collection) Find(ctx context.Context, filter interface{}) QueryI {
return &Query{
ctx: ctx,
collection: c.collection,
filter: filter,
}
}
// InsertOne insert one document into the collection
// Reference: https://docs.mongodb.com/manual/reference/command/insert/
func (c *Collection) InsertOne(ctx context.Context, doc interface{}) (result *InsertOneResult, err error) {
res, err := c.collection.InsertOne(ctx, doc)
if res != nil {
result = &InsertOneResult{InsertedID: res.InsertedID}
}
return
}
// InsertMany executes an insert command to insert multiple documents into the collection.
// e.g. docs := []interface{}{myDocsInstance1, myDocsInstance2}
// TODO need a function which translate slice to []interface
// Reference: https://docs.mongodb.com/manual/reference/command/insert/
func (c *Collection) InsertMany(ctx context.Context, docs []interface{}) (result *InsertManyResult, err error) {
res, err := c.collection.InsertMany(ctx, docs)
if res != nil {
result = &InsertManyResult{InsertedIDs: res.InsertedIDs}
}
return
}
// Upsert updates one documents if filter match, inserts one document if filter is not match
// Reference: https://docs.mongodb.com/manual/reference/operator/update/
func (c *Collection) Upsert(ctx context.Context, filter interface{}, replacement interface{}) (result *UpdateResult, err error) {
opts := options.Replace().SetUpsert(true)
res, err := c.collection.ReplaceOne(ctx, filter, replacement, opts)
if res != nil {
result = translateUpdateResult(res)
}
return
}
// UpdateOne executes an update command to update at most one document in the collection.
// Reference: https://docs.mongodb.com/manual/reference/operator/update/
func (c *Collection) UpdateOne(ctx context.Context, filter interface{}, update interface{}) error {
var err error
var res *mongo.UpdateResult
if res, err = c.collection.UpdateOne(ctx, filter, update); err != nil {
return err
}
if res.MatchedCount == 0 {
err = ErrNoSuchDocuments
}
return err
}
// UpdateAll executes an update command to update documents in the collection.
// The matchedCount is 0 in UpdateResult if no document updated
// Reference: https://docs.mongodb.com/manual/reference/operator/update/
func (c *Collection) UpdateAll(ctx context.Context, filter interface{}, update interface{}) (result *UpdateResult, err error) {
res, err := c.collection.UpdateMany(ctx, filter, update)
if res != nil {
result = translateUpdateResult(res)
}
return
}
// Remove executes a delete command to delete at most one document from the collection.
// if filter is bson.M{},DeleteOne will delete one document in collection
// Reference: https://docs.mongodb.com/manual/reference/command/delete/
func (c *Collection) Remove(ctx context.Context, filter interface{}) (err error) {
res, err := c.collection.DeleteOne(ctx, filter)
if err != nil {
return err
}
if res.DeletedCount == 0 {
err = ErrNoSuchDocuments
}
return err
}
// RemoveId executes a delete command to delete at most one document from the collection.
func (c *Collection) RemoveId(ctx context.Context, id string) (err error) {
res, err := c.collection.DeleteOne(ctx, bson.M{"_id": id})
if err != nil {
return err
}
if res.DeletedCount == 0 {
err = ErrNoSuchDocuments
}
return err
}
// DeleteAll executes a delete command to delete documents from the collection.
// If filter is bson.M{},all ducuments in Collection will be deleted
// Reference: https://docs.mongodb.com/manual/reference/command/delete/
func (c *Collection) DeleteAll(ctx context.Context, filter interface{}) (result *DeleteResult, err error) {
res, err := c.collection.DeleteMany(ctx, filter)
if res != nil {
result = &DeleteResult{DeletedCount: res.DeletedCount}
}
return
}
// Aggregate executes an aggregate command against the collection and returns a AggregateI to get resulting documents.
func (c *Collection) Aggregate(ctx context.Context, pipeline interface{}) AggregateI {
return &Aggregate{
ctx: ctx,
collection: c.collection,
pipeline: pipeline,
}
}
// ensureIndex create multiple indexes on the collection and returns the names of
// Example:indexes = []string{"idx1", "-idx2", "idx3,idx4"}
// Three indexes will be created, index idx1 with ascending order, index idx2 with descending order, idex3 and idex4 are Compound ascending sort index
// Reference: https://docs.mongodb.com/manual/reference/command/createIndexes/
func (c *Collection) ensureIndex(ctx context.Context, indexes []string, isUnique bool) {
var indexModels []mongo.IndexModel
// 组建[]mongo.IndexModel
for _, idx := range indexes {
var model mongo.IndexModel
var keysDoc bsonx.Doc
colIndexArr := strings.Split(idx, ",")
for _, field := range colIndexArr {
key, n := SplitSortField(field)
keysDoc = keysDoc.Append(key, bsonx.Int32(n))
}
model = mongo.IndexModel{
Keys: keysDoc,
Options: options.Index().SetUnique(isUnique),
}
indexModels = append(indexModels, model)
}
if len(indexModels) == 0 {
return
}
var err error
var res []string
res, err = c.collection.Indexes().CreateMany(ctx, indexModels)
if err != nil || len(res) == 0 {
s := fmt.Sprint("<MongoDB.C>: ", c.collection.Name(), " Index: ", indexes, " error: ", err, "res: ", res)
panic(s)
}
return
}
// EnsureIndexes creates unique and non-unique indexes in collection
func (c *Collection) EnsureIndexes(ctx context.Context, uniques []string, indexes []string) {
// 创建唯一索引
if len(uniques) != 0 {
c.ensureIndex(ctx, uniques, true)
}
// 创建普通索引
if len(indexes) != 0 {
c.ensureIndex(ctx, indexes, false)
}
return
}
// DropCollection drops collection
// it's safe even collection is not exists
func (c *Collection) DropCollection(ctx context.Context) error {
return c.collection.Drop(ctx)
}
// CloneCollection creates a copy of the Collection
func (c *Collection) CloneCollection() (*mongo.Collection, error) {
return c.collection.Clone()
}
// GetCollectionName returns the name of collection
func (c *Collection) GetCollectionName() string {
return c.collection.Name()
}
// translateUpdateResult translates mongo update result to qmgo define UpdateResult
func translateUpdateResult(res *mongo.UpdateResult) (result *UpdateResult) {
result = &UpdateResult{
MatchedCount: res.MatchedCount,
ModifiedCount: res.ModifiedCount,
UpsertedCount: res.UpsertedCount,
UpsertedID: res.UpsertedID,
}
return
}