mongo.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package tool
  2. import (
  3. "context"
  4. "fmt"
  5. "go.mongodb.org/mongo-driver/bson"
  6. "go.mongodb.org/mongo-driver/mongo"
  7. "go.mongodb.org/mongo-driver/mongo/options"
  8. )
  9. type Config struct {
  10. Uri string
  11. Database string
  12. Username string
  13. Password string
  14. }
  15. // MongoRepo 保存 MongoDB 数据库实例的结构体
  16. type MongoRepo struct {
  17. DB *mongo.Database
  18. }
  19. // InitMongo 初始化 MongoDB 连接,成功后返回 MongoRepo 结构体
  20. func InitMongo(cfg Config) (*MongoRepo, error) {
  21. // 设置 MongoDB 客户端选项
  22. clientOptions := options.Client().ApplyURI(cfg.Uri)
  23. if cfg.Username != "" && cfg.Password != "" {
  24. clientOptions = clientOptions.SetAuth(options.Credential{
  25. Username: cfg.Username,
  26. Password: cfg.Password,
  27. })
  28. }
  29. // 连接到 MongoDB
  30. client, err := mongo.Connect(context.TODO(), clientOptions)
  31. if err != nil {
  32. return nil, err
  33. }
  34. // 检查连接
  35. err = client.Ping(context.TODO(), nil)
  36. if err != nil {
  37. // 连接失败时断开连接
  38. _ = client.Disconnect(context.TODO())
  39. return nil, err
  40. }
  41. // 获取数据库实例
  42. db := client.Database(cfg.Database)
  43. return &MongoRepo{
  44. DB: db,
  45. }, nil
  46. }
  47. // InsertOne 向指定集合中插入单个文档
  48. func (mr *MongoRepo) InsertOne(ctx context.Context, collectionName string, document interface{}) (*mongo.InsertOneResult, error) {
  49. collection := mr.DB.Collection(collectionName)
  50. return collection.InsertOne(ctx, document)
  51. }
  52. // Upsert 执行更新时插入操作
  53. /*
  54. 在 MongoDB 里, upsert 是一种特殊的更新行为:
  55. - 若更新操作的查询条件能匹配到文档,就按照指定的更新规则修改这些文档。
  56. - 若查询条件没有匹配到任何文档,就会根据查询条件和更新规则插入一个新的文档。
  57. */
  58. func (mr *MongoRepo) Upsert(ctx context.Context, collectionName string, filter interface{}, update interface{}) (*mongo.UpdateResult, error) {
  59. // 获取集合
  60. collection := mr.DB.Collection(collectionName)
  61. // 设置更新选项,开启 upsert
  62. opts := options.Update().SetUpsert(true)
  63. // 执行更新操作
  64. return collection.UpdateOne(ctx, filter, update, opts)
  65. }
  66. // NestedQuery 执行嵌套查询,返回匹配的文档游标 如address.city
  67. func (mr *MongoRepo) NestedQuery(ctx context.Context, collectionName string, nestedFilter interface{}, opts ...*options.FindOptions) (*mongo.Cursor, error) {
  68. collection := mr.DB.Collection(collectionName)
  69. return collection.Find(ctx, nestedFilter, opts...)
  70. }
  71. // QueryEmbeddedDocument 查询嵌入式文档,返回匹配的文档游标
  72. func (mr *MongoRepo) QueryEmbeddedDocument(ctx context.Context, collectionName string, embeddedFilter interface{}, opts ...*options.FindOptions) (*mongo.Cursor, error) {
  73. collection := mr.DB.Collection(collectionName)
  74. return collection.Find(ctx, embeddedFilter, opts...)
  75. }
  76. // QueryArrayContains 查询数组字段包含特定元素的文档,返回匹配的文档游标
  77. func (mr *MongoRepo) QueryArrayContains(ctx context.Context, collectionName string, arrayField string, elements []interface{}, opts ...*options.FindOptions) (*mongo.Cursor, error) {
  78. filter := bson.M{
  79. arrayField: bson.M{
  80. "$in": elements,
  81. },
  82. }
  83. collection := mr.DB.Collection(collectionName)
  84. return collection.Find(ctx, filter, opts...)
  85. }
  86. // QueryArrayWithComplexFilter 通过复合筛选条件查询数组元素,返回匹配的文档游标
  87. func (mr *MongoRepo) QueryArrayWithComplexFilter(ctx context.Context, collectionName string, arrayField string, complexFilter bson.M, opts ...*options.FindOptions) (*mongo.Cursor, error) {
  88. filter := bson.M{
  89. arrayField: bson.M{
  90. "$elemMatch": complexFilter,
  91. },
  92. }
  93. collection := mr.DB.Collection(collectionName)
  94. return collection.Find(ctx, filter, opts...)
  95. }
  96. // QueryArrayElementByIndex 按数组索引位置查询元素,返回匹配的文档游标
  97. func (mr *MongoRepo) QueryArrayElementByIndex(ctx context.Context, collectionName string, arrayField string, index int, opts ...*options.FindOptions) (*mongo.Cursor, error) {
  98. // 构建查询字段,使用点表示法访问数组索引
  99. field := fmt.Sprintf("%s.%d", arrayField, index)
  100. // 构建查询条件,这里查询该索引位置有值的文档
  101. filter := bson.M{
  102. field: bson.M{
  103. "$exists": true,
  104. },
  105. }
  106. collection := mr.DB.Collection(collectionName)
  107. return collection.Find(ctx, filter, opts...)
  108. }