使用Golang实现MongoDB Shell功能

使用Golang实现MongoDB Shell功能 我的数据在MongoDB中以树形结构模型存储。以下是我的数据结构:

image

以下是我用于创建集合的Mongo Shell脚本:

db.users.insert({_id:"DHBK",username:"DHBK",password:"123456",lastname:"DHBK",user_email:"dhbk@edu.com.vn",user_tel:"0907111001",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:null,com_id:"DHBK",com_department:"DHBK",user_code:"DHBK_0001",user_type:"ADMIN_COM"});
db.users.insert({_id:"KHOA_DIEN",username:"KHOA_DIEN",password:"123456",lastname:"KHOA_DIEN",user_email:"KHOA_DIEN@edu.com.vn",user_tel:"0907111002",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"DHBK",com_id:"DHBK",com_department:"KHOA_DIEN",user_code:"DHBK_0002",user_type:"USER_COM"});
db.users.insert({_id:"KHOA_XD",username:"KHOA_XD",password:"123456",lastname:"KHOA_XD",user_email:"KHOA_XD@edu.com.vn",user_tel:"0907111003",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"DHBK",com_id:"DHBK",com_department:"KHOA_XD",user_code:"DHBK_0003",user_type:"USER_COM"});
db.users.insert({_id:"KHOA_CNTT",username:"KHOA_CNTT",password:"123456",lastname:"KHOA_CNTT",user_email:"KHOA_CNTT@edu.com.vn",user_tel:"0907111004",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"DHBK",com_id:"DHBK",com_department:"KHOA_CNTT",user_code:"DHBK_0004",user_type:"USER_COM"});
db.users.insert({_id:"BOMON_TUDONG",username:"BOMON_TUDONG",password:"123456",lastname:"BOMON_TUDONG",user_email:"BOMON_TUDONG@edu.com.vn",user_tel:"0907111005",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"KHOA_DIEN",com_id:"DHBK",com_department:"KHOA_DIEN",user_code:"DHBK_0005",user_type:"USER_COM"});
db.users.insert({_id:"BOMON_VIENTHONG",username:"BOMON_VIENTHONG",password:"123456",lastname:"BOMON_VIENTHONG",user_email:"BOMON_VIENTHONG@edu.com.vn",user_tel:"0907111006",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"KHOA_DIEN",com_id:"DHBK",com_department:"KHOA_DIEN",user_code:"DHBK_0006",user_type:"USER_COM"});
db.users.insert({_id:"BOMON_HETHONG",username:"BOMON_HETHONG",password:"123456",lastname:"BOMON_HETHONG",user_email:"BOMON_HETHONG@edu.com.vn",user_tel:"0907111007",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"KHOA_DIEN",com_id:"DHBK",com_department:"KHOA_DIEN",user_code:"DHBK_0007",user_type:"USER_COM"});
db.users.insert({_id:"BOMON1_XD",username:"BOMON1_XD",password:"123456",lastname:"BOMON1_XD",user_email:"BOMON1_XD@edu.com.vn",user_tel:"0907111008",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"KHOA_XD",com_id:"DHBK",com_department:"KHOA_XD",user_code:"DHBK_0008",user_type:"USER_COM"});
db.users.insert({_id:"BOMON2_XD",username:"BOMON2_XD",password:"123456",lastname:"BOMON2_XD",user_email:"BOMON2_XD@edu.com.vn",user_tel:"0907111009",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"KHOA_XD",com_id:"DHBK",com_department:"KHOA_XD",user_code:"DHBK_0009",user_type:"USER_COM"});
db.users.insert({_id:"BOMON3_XD",username:"BOMON3_XD",password:"123456",lastname:"BOMON3_XD",user_email:"BOMON3_XD@edu.com.vn",user_tel:"0907111010",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"KHOA_XD",com_id:"DHBK",com_department:"KHOA_XD",user_code:"DHBK_0010",user_type:"USER_COM"});
db.users.insert({_id:"TRUONGKHOA_BMVT",username:"TRUONGKHOA_BMVT",password:"123456",lastname:"TRUONGKHOA_BMVT",user_email:"TRUONGKHOA_BMVT@edu.com.vn",user_tel:"0907111011",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"BOMON_VIENTHONG",com_id:"DHBK",com_department:"BOMON_VIENTHONG",user_code:"DHBK_0011",user_type:"USER_COM"});
db.users.insert({_id:"PHOKHOA_BMVT",username:"PHOKHOA_BMVT",password:"123456",lastname:"PHOKHOA_BMVT",user_email:"PHOKHOA_BMVT@edu.com.vn",user_tel:"0907111012",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"BOMON_VIENTHONG",com_id:"DHBK",com_department:"BOMON_VIENTHONG",user_code:"DHBK_0012",user_type:"USER_COM"});
db.users.insert({_id:"THUKY_BMVT",username:"THUKY_BMVT",password:"123456",lastname:"THUKY_BMVT",user_email:"THUKY_BMVT@edu.com.vn",user_tel:"0907111013",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"BOMON_VIENTHONG",com_id:"DHBK",com_department:"BOMON_VIENTHONG",user_code:"DHBK_0013",user_type:"USER_COM"});
db.users.insert({_id:"GV_BMVT",username:"GV_BMVT",password:"123456",lastname:"GV_BMVT",user_email:"GV_BMVT@edu.com.vn",user_tel:"0907111014",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"BOMON_VIENTHONG",com_id:"DHBK",com_department:"BOMON_VIENTHONG",user_code:"DHBK_0014",user_type:"USER_COM"});
db.users.insert({_id:"SV1_BMVT",username:"SV1_BMVT",password:"123456",lastname:"SV1_BMVT",user_email:"SV1_BMVT@edu.com.vn",user_tel:"0907111015",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"GV_BMVT",com_id:"DHBK",com_department:"BOMON_VIENTHONG",user_code:"DHBK_0015",user_type:"USER_COM"});
db.users.insert({_id:"SV2_BMVT",username:"SV2_BMVT",password:"123456",lastname:"SV2_BMVT",user_email:"SV2_BMVT@edu.com.vn",user_tel:"0907111016",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"GV_BMVT",com_id:"DHBK",com_department:"BOMON_VIENTHONG",user_code:"DHBK_0016",user_type:"USER_COM"});
db.users.insert({_id:"SV3_BMVT",username:"SV3_BMVT",password:"123456",lastname:"SV3_BMVT",user_email:"SV3_BMVT@edu.com.vn",user_tel:"0907111017",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"GV_BMVT",com_id:"DHBK",com_department:"BOMON_VIENTHONG",user_code:"DHBK_0017",user_type:"USER_COM"});
db.users.insert({_id:"SV4_BMVT",username:"SV4_BMVT",password:"123456",lastname:"SV4_BMVT",user_email:"SV4_BMVT@edu.com.vn",user_tel:"0907111018",user_date:"2020-05-05",user_status:"ACTIVE",user_parentid:"GV_BMVT",com_id:"DHBK",com_department:"BOMON_VIENTHONG",user_code:"DHBK_0018",user_type:"USER_COM"});

在我的实践中,我想删除父节点,这意味着要删除所有后代节点。

例如: 当我删除 “BOMON_VIENTHONG” 节点时,必须同时删除 TRUONGKHOA_BMVT、PHOKHOA_BMVT、THUKY_BMVT、GV_BMVT、SV1_BMVT、SV2_BMVT、SV3_BMVT、SV4_BMVT。

我可以使用Mongo Shell来执行这个删除操作。以下是我的Mongo Shell脚本:

TOP_LEVEL_PARENT = "BOMON_VIENTHONG"
db.users.aggregate( [
   {
      $graphLookup: {
      from: "users",
      startWith: "$user_parentid",
      connectFromField: "user_parentid",
      connectToField: "_id",
      as: "hierarchy"
      }
   },
  { 
  $match: { 
      $or: [ 
         { "hierarchy._id":  TOP_LEVEL_PARENT },
         { _id: TOP_LEVEL_PARENT }
          ]
      } 
  }
] 
).forEach( doc => db.users.deleteOne( { _id: doc._id } ) )

我想在Go语言中实现这个Mongo Shell脚本。我是Go语言的初学者。

请帮助我。

提前感谢。


更多关于使用Golang实现MongoDB Shell功能的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

尝试一个用于 MongoDB 的驱动程序:

https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo?tab=doc

更多关于使用Golang实现MongoDB Shell功能的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我正在使用 mgo。 但这个语法对我来说非常复杂。 请帮我将其转换为 mgo 语法。

TOP_LEVEL_PARENT = "BOMON_VIENTHONG"
db.users.aggregate( [
   {
      $graphLookup: {
          from: "users",
          startWith: "$user_parentid",
          connectFromField: "user_parentid",
          connectToField: "_id",
          as: "hierarchy"
      }
   },
  { 
      $match: { 
          $or: [ 
             { "hierarchy._id":  TOP_LEVEL_PARENT },
             { _id: TOP_LEVEL_PARENT }
          ]
      } 
  }
] 
).forEach( doc => db.users.deleteOne( { _id: doc._id } ) )

在Go语言中实现MongoDB Shell的树形结构删除功能,可以使用官方的MongoDB Go驱动。以下是完整的示例代码:

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

type User struct {
    ID           string `bson:"_id"`
    Username     string `bson:"username"`
    Password     string `bson:"password"`
    Lastname     string `bson:"lastname"`
    UserEmail    string `bson:"user_email"`
    UserTel      string `bson:"user_tel"`
    UserDate     string `bson:"user_date"`
    UserStatus   string `bson:"user_status"`
    UserParentID string `bson:"user_parentid"`
    ComID        string `bson:"com_id"`
    ComDepartment string `bson:"com_department"`
    UserCode     string `bson:"user_code"`
    UserType     string `bson:"user_type"`
}

func deleteNodeAndDescendants(parentID string) error {
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
    if err != nil {
        return fmt.Errorf("连接MongoDB失败: %v", err)
    }
    defer client.Disconnect(ctx)

    collection := client.Database("test").Collection("users")

    pipeline := mongo.Pipeline{
        bson.D{
            {"$graphLookup", bson.D{
                {"from", "users"},
                {"startWith", "$user_parentid"},
                {"connectFromField", "user_parentid"},
                {"connectToField", "_id"},
                {"as", "hierarchy"},
            }},
        },
        bson.D{
            {"$match", bson.D{
                {"$or", bson.A{
                    bson.D{{"hierarchy._id", parentID}},
                    bson.D{{"_id", parentID}},
                }},
            }},
        },
    }

    cursor, err := collection.Aggregate(ctx, pipeline)
    if err != nil {
        return fmt.Errorf("聚合查询失败: %v", err)
    }
    defer cursor.Close(ctx)

    var usersToDelete []User
    if err = cursor.All(ctx, &usersToDelete); err != nil {
        return fmt.Errorf("读取结果失败: %v", err)
    }

    for _, user := range usersToDelete {
        _, err := collection.DeleteOne(ctx, bson.D{{"_id", user.ID}})
        if err != nil {
            return fmt.Errorf("删除用户 %s 失败: %v", user.ID, err)
        }
        fmt.Printf("已删除: %s\n", user.ID)
    }

    fmt.Printf("成功删除 %d 个节点\n", len(usersToDelete))
    return nil
}

func main() {
    parentID := "BOMON_VIENTHONG"
    
    if err := deleteNodeAndDescendants(parentID); err != nil {
        log.Fatal(err)
    }
}

如果需要更高效的递归删除实现,可以使用以下方法:

func deleteNodeAndDescendantsRecursive(parentID string) error {
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
    if err != nil {
        return fmt.Errorf("连接MongoDB失败: %v", err)
    }
    defer client.Disconnect(ctx)

    collection := client.Database("test").Collection("users")

    var deleteIDs []string
    deleteIDs = append(deleteIDs, parentID)

    for i := 0; i < len(deleteIDs); i++ {
        currentID := deleteIDs[i]
        
        cursor, err := collection.Find(ctx, bson.D{{"user_parentid", currentID}})
        if err != nil {
            return fmt.Errorf("查找子节点失败: %v", err)
        }

        var children []User
        if err = cursor.All(ctx, &children); err != nil {
            cursor.Close(ctx)
            return fmt.Errorf("读取子节点失败: %v", err)
        }
        cursor.Close(ctx)

        for _, child := range children {
            deleteIDs = append(deleteIDs, child.ID)
        }
    }

    for _, id := range deleteIDs {
        _, err := collection.DeleteOne(ctx, bson.D{{"_id", id}})
        if err != nil {
            return fmt.Errorf("删除节点 %s 失败: %v", id, err)
        }
        fmt.Printf("已删除: %s\n", id)
    }

    fmt.Printf("成功删除 %d 个节点\n", len(deleteIDs))
    return nil
}

使用BulkWrite进行批量删除的优化版本:

func deleteNodeAndDescendantsBulk(parentID string) error {
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
    if err != nil {
        return fmt.Errorf("连接MongoDB失败: %v", err)
    }
    defer client.Disconnect(ctx)

    collection := client.Database("test").Collection("users")

    pipeline := mongo.Pipeline{
        bson.D{
            {"$graphLookup", bson.D{
                {"from", "users"},
                {"startWith", "$user_parentid"},
                {"connectFromField", "user_parentid"},
                {"connectToField", "_id"},
                {"as", "hierarchy"},
                {"maxDepth", 10},
                {"depthField", "depth"},
            }},
        },
        bson.D{
            {"$match", bson.D{
                {"$or", bson.A{
                    bson.D{{"hierarchy._id", parentID}},
                    bson.D{{"_id", parentID}},
                }},
            }},
        },
        bson.D{
            {"$project", bson.D{
                {"_id", 1},
            }},
        },
    }

    cursor, err := collection.Aggregate(ctx, pipeline)
    if err != nil {
        return fmt.Errorf("聚合查询失败: %v", err)
    }
    defer cursor.Close(ctx)

    var results []bson.M
    if err = cursor.All(ctx, &results); err != nil {
        return fmt.Errorf("读取结果失败: %v", err)
    }

    var models []mongo.WriteModel
    for _, result := range results {
        id := result["_id"].(string)
        model := mongo.NewDeleteOneModel().SetFilter(bson.D{{"_id", id}})
        models = append(models, model)
    }

    if len(models) > 0 {
        opts := options.BulkWrite().SetOrdered(false)
        result, err := collection.BulkWrite(ctx, models, opts)
        if err != nil {
            return fmt.Errorf("批量删除失败: %v", err)
        }
        fmt.Printf("成功删除 %d 个文档\n", result.DeletedCount)
    }

    return nil
}

安装MongoDB Go驱动:

go get go.mongodb.org/mongo-driver/mongo

这些代码实现了与Mongo Shell脚本相同的功能,可以删除指定节点及其所有后代节点。

回到顶部