golang

Golang MongoDB 튜토리얼

youngmki 2022. 1. 2. 04:50

MongoDB는 오픈 소스 NoSQL 데이터베이스로, 문서 지향 데이터 베이스(document-oriented database)라는 특징을 가집니다. 특이한 것은 BSON이라는 JSON과 유사한 구조를 사용하여 문서(key-value)를 저장합니다. 해당 글에서는 golang에서 MongoDB 를 사용하는 가장 기본적인 5가지(연결, 삽입, 삭제, 검색, 업데이트) 를 다룹니다.

기본 전제: MongoDB가 이미 설치되어있어야 하고, 27017 포트에서 시작해야 합니다.

참고

포트 설명
27017 서비스 기본 포트
27018 --shardsvr 서비스 포트
27019 --configsvr 기본 포트
28017 웹 상태 페이지 기본 포트

 

mongo 패키지는 Go를 위한 MongoDB Driver API를 제공합니다. MongoDB API와 통신하기 위해서는 Driver API가 필요합니다.

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

1. 연결


코드에서는 다음 작업을 수행합니다.

  1. mongo.Connect 함수를 통해 mongo.Client를 생성합니다. 이때, mongo.Client는 MongoDB와의 연결을 처리합니다.
  2. mongo.Client에는 성공적인 연결에 대한 결과를 내보내는 Ping이라는 메소드가 있습니다.
  3. 메인함수의 종료와 함께 contextDisconnect 라는 메소드를 통해 데이터 베이스 연결을 닫습니다.
// ** connection.go ** 
package main

import (
    "context"
    "fmt"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo-driver/mongo/readpref"
    "time"
)

// 리소스를 Close 하기 위한 메소드
// mongoDB의 연결을 Close
// context를 Close 합니다.
func close(client *mongo.Client, ctx context.Context, cancel context.CancelFunc) {

    // context를 cancel 하기 위한 CancelFunc
    defer cancel()

    // mongoDB 연결을 종료하기 위한 클로저
    defer func() {
        // client.Disconnect 메소드를 실행
        // 에러가 있다면 프로그램 강제 종료 (panic으로 나가게 되면 기존의 defer 함수가 모두 실행된 이후 즉시 리턴)
        if err := client.Disconnect(ctx); err != nil {
            panic(err)
        }

    }()
}

// mongo.Client를 반환하는 메소드
// 이때 mongo.Client는 데이터베이스 작업에 사용
// context.CancelFunc은 관련된 context와 관련된 리소스를 모두 cancel하는데 사용
func connect(uri string) (client *mongo.Client, ctx context.Context, cancel context.CancelFunc, err error) {

    // ctx는 프로세스의 데드라인을 설정하기 위해 사용
    // 이때, deadline은 30 초로 설정
    ctx, cancel = context.WithTimeout(context.Background(), 30 * time.Second)

    // DB 연결에 사용하기 위한 mongo.Client 객체
    client, err = mongo.Connect(ctx, options.Client().ApplyURI(uri))

    // 이때 별도의 패닉 처리 없이 이후 ping 에서 한번에 처리
    return client, ctx, cancel, err
}

// mongo.Client와 context.Context의 생성이 성공적으로 수행되었는지를 반환
// mongoDB에 ping, 에러가 있다면 이를 반환
func ping(client *mongo.Client, ctx context.Context) error {

    // ctx에서 지정한 deadline을 기준으로 mongo.Client는 mongoDB에 ping
    // ping 메소드는 error를 발생시키고, 이를 통해 error handle
    if err := client.Ping(ctx, readpref.Primary()); err != nil {
        return err
    }
    fmt.Println("Connected Successfully")
    return nil
}

func main() {
    // Client, Context, CancelFun, err 생성
    client, ctx, cancel, err := connect("mongodb://localhost:27017"); if err != nil {
        panic(err)
    }

    // main 함수가 리턴되기 전에 모든 리소스를 Release
    defer close(client, ctx, cancel)

    // Ping 메소드를 활용하여 mongoDB에 ping
    ping(client, ctx)
}

2. 삽입


Document를 삽입하는 내용에 대해서 다루고 있습니다.

Document라는 용어가 생소할 텐데, mongoDB에서는 Row를 Document라고 합니다.

관계형 DB에서는 column이 모여 row를 이루고 row가 모여 하나의 Table을 구성합니다. 이때 하나의 row는 동일한 수와 종류의 column을 하나의 column은 동일한 수와 종류의 row를 갖게 되는데, 이런 정형화된 구조는 SQL을 사용하여 원하는 결과를 빠르게 찾게 한다는 이점을 가짐과 동시에 모든 레코드에 동일한 저장 공간을 가져야 한다는 비효율성을 함께 가집니다.

반면 mongoDB의 경우 저장되는 데이터의 형식이 정해져 있지 않고 비정형화된 구조를 지닙니다. 레코드마다 정보의 구조가 다를 수 있으며, 때문에 자료 형식에 자유를 좀 더 부여하는 대신 검색 속도가 기존 SQL이 가졌던 속도보다 느리다는 사이드 이펙트가 존재합니다.

RMDB의 데이터 저장과 MongoDB의 데이터저장

이 외에도 다른 용어들이 기존 데이터베이스와 달리 사용되는 경우가 많은데 일부를 정리하였습니다.

관계형 DB mongoDB
TABLE Collection
Row Document
Index Index
Join Embedded Document
Foreign Key Reference
Partition Shard

코드에서는 다음 순서로 작업을 진행합니다.

  1. mongoDB client 함수로 mongo.Client를 생성합니다. mongo.Client는 MongoDB와의 연결을 처리하게 됩니다.
  2. mongo.Client.Database는 데이터베이스에 대한 포인터를 반환합니다.
  3. 데이터베이스에 대한 포인터에는 작업을 진행할 collection을 찾기 위한 메소드 collection이 있습니다.
  4. collection 타입에는 문서를 삽입하기 위한 두 가지 방법을 제공합니다.
  5. Collection.InsertOne() 메서드를 통해서는 하나의 Document를 데이터베이스에 삽입할 수 있습니다.
  6. Collection.InsertMany() 메서드를 통해서는 Document의 리스트를 데이터베이스에 삽입할 수 있습니다.
  7. 삽입이 완료되었다면, mongo.Client.Disconnect를 통해 데이터베이스의 연결을 닫습니다.
package main

import (
    "context"
    "fmt"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "time"
)

// 리소스를 Close 하기 위한 메소드
// context close 와 client disconnect 처리
func close(client *mongo.Client, ctx context.Context, cancel context.CancelFunc) {

    defer cancel()
    defer func() {
        if err := client.Disconnect(ctx); err != nil {
            panic(err)
        }
    }()
}

// 연결을 생성하고, 관련 리소스를 반환하는 메소드
// mongo.Client: DB를 사용하는 Client
// context.Context: 문제가 발생하면 function call 차단하기 위해 활용
//    ex. timeout 발생시 생성한 context 전달하여 제어 가능
//    해당 코드에서는 데이터베이스 connection이 너무 길어지는 것을 방지
//    지정한 시간이 지난 후에 context에 다시 접근하려고 하는 경우
//    TimeOut에 따라서 다음의 오류 발생 -> "context deadline exceeded"
// context.CancelFunc: CancelFunc를 호출 시 자식과 이와 그 하위 자식들이 cancel, 자식들의 부모에 대한 참조가 모두 제거, 연결된 타이머 중지
func connect(url string)(client *mongo.Client, ctx context.Context, cancel context.CancelFunc, err error) {

    ctx, cancel = context.WithTimeout(context.Background(), 30 * time.Second)
    client, err = mongo.Connect(ctx, options.Client().ApplyURI(url))
    return client, ctx, cancel, err
}

// Document collection 내부로 단일 insert 를 수행하는 메소드
// insert 결과와 에러를 반환
func insertOne(client *mongo.Client, ctx context.Context,
    dataBase, col string, doc interface{}) (*mongo.InsertOneResult, error) {

    // Client.Database 메소드를 통해 작업하고자 하는 Database, Collection 선택
    collection := client.Database(dataBase).Collection(col)

    // InsertMany 메소드는 Context 타입과 함께 empty interface 요구
    result, err := collection.InsertOne(ctx, doc)
    return result, err
}

// Document collection 내부로 여러 insert 를 수행하는 메소드
// insert 결과와 에러를 반환
func insertMany (client *mongo.Client, ctx context.Context,
    database, col string, docs []interface{}) (*mongo.InsertManyResult, error) {

    // Client.Database 메소드를 통해 작업하고자 하는 Database, Collection 선택
    collection := client.Database(database).Collection(col)

    // InsertMany 메소드는 Context 타입과 함께 empty interface 요구
    result, err := collection.InsertMany(ctx, docs)
    return result, err
}

func main() {

    // client, context, cancelFun, err 생성
    client, ctx, cancel, err := connect("mongodb://localhost:27017")
    if err != nil {
        panic(err)
    }

    // main 함수가 종료되면 모든 리소스 반환할 수 있도록 defer 통해 호출
    defer close(client, ctx, cancel)

    // ---------------------------------------------------------------------------
    // MongoDB에 들어갈 bson 값들을 저장하기 위해 interface 객체를 생성
    var document interface{}
    document = bson.D{
        {"rollNo", 175},
        {"maths", 80},
        {"science", 90},
        {"computer", 95},
    }

    // arg: client, context, database name, collection name, 삽입될 doc interface
    // 삽입의 결과와 에러를 반환
    insertOneResult, err := insertOne(client, ctx, "gfg", "marks", document)
    if err != nil {
        panic(err)
    }

    // 삽입이 완료되었다면 insertion id 출력
    fmt.Println("Result of InsertOne")
    fmt.Println(insertOneResult.InsertedID)

    // ---------------------------------------------------------------------------
    // MongoDB에 들어갈 bson 값들을 저장하기 위해 interface 슬라이스 객체를 생성
    var documents []interface{}
    documents = []interface{}{
        bson.D {
            {"rollNo", 175},
            {"maths", 80},
            {"science", 90},
            {"computer", 95},
        },
        bson.D {
            {"rollNo", 105},
            {"maths", 110},
            {"science", 120},
            {"computer", 195},
        },
    }

    // arg: client, context, database name, collection name, 삽입될 doc interface slice
    // 삽입의 결과와 에러를 리턴
    // 삽입 중 하나라도 에러가 있을 경우 에러를 채워서 반환
    insertmanyResult, err := insertMany(client, ctx, "gfg", "marks", documents)
    if err != nil {
        panic(err)
    }
    fmt.Println("Result of Insertmany")

    // 삽입이 완료되었다면 각 삽입에 대한 insertion id 출력
    for id := range insertmanyResult.InsertedIDs {
        fmt.Println(id)
    }
}

bson의 종류

  • bson.D: 하나의 BSON 도큐멘트. MongoDB command 처럼 순서가 중요한 경우에 사용합니다.
  • bson.M: 순서가 없는 map 형태. 순서를 유지하지 않는다는 점을 빼면 D와 같습니다.
  • bson.A: 하나의 BSON array 형태.
  • bson.E: D 타입 내부에서 사용하는 하나의 엘레멘트.

3. 삭제


코드에서는 다음 순서로 작업을 진행합니다.

  1. mongoDB client 함수로 mongo.Client를 생성합니다. mongo.Client는 MongoDB와의 연결을 처리하게 됩니다.
  2. mongo.Client.Database는 데이터베이스에 대한 포인터를 반환합니다.
  3. 데이터베이스에 대한 포인터에는 작업을 진행할 collection을 찾기 위한 메소드 collection이 있습니다.
  4. collection 타입에는 문서를 삭제하기 위한 두 가지 방법을 제공합니다.
  5. DeleteOne() 함수는 쿼리와 일치하는 단일 문서를 제거합니다.
  6. DeleteMany() 함수는 쿼리와 일치하는 모든 문서를 제거합니다.
  7. 작업이 마무리되었다면 mongo.Client.Disconnect 를 사용하여 데이터베이스 연결을 닫습니다.
package main

import (
    "context"
    "fmt"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "time"
)

// 리소스를 Close 하기 위한 메소드
// context close 와 client disconnect 처리
func close(client *mongo.Client, ctx context.Context, cancel context.CancelFunc) {

    defer cancel()

    defer func() {
        if err := client.Disconnect(ctx); err != nil {
            panic(err)
        }
    } ()
}

// 연결을 생성하고, 관련 리소스를 반환하는 메소드
// mongo.Client: DB를 사용하는 Client
// context.Context: 문제가 발생하면 function call 차단하기 위해 활용
//        ex. timeout 발생시 생성한 context 전달하여 제어 가능
//        해당 코드에서는 데이터베이스 connection이 너무 길어지는 것을 방지
//        지정한 시간이 지난 후에 context에 다시 접근하려고 하는 경우
//        TimeOut에 따라서 다음의 오류 발생 -> "context deadline exceeded"
// context.CancelFunc: CancelFunc를 호출 시 자식과 이와 그 하위 자식들이 cancel, 자식들의 부모에 대한 참조가 모두 제거, 연결된 타이머 중지
func connect (url string) (client *mongo.Client, ctx context.Context, cancel context.CancelFunc, err error) {

    ctx, cancel = context.WithTimeout(ctx, 30 * time.Second)
    client, err = mongo.Connect(ctx, options.Client().ApplyURI(url))

    return client, ctx, cancel, err
}

// collection 내부로 단일 document delete 를 수행하는 메소드
// delete 결과와 에러를 반환
func deleteOne(client *mongo.Client, ctx context.Context,
    dataBase, col string, query interface{}) (delResult *mongo.DeleteResult, err error) {

    // Client.Database 메소드를 통해 작업하고자 하는 Database, Collection 선택
    collection := client.Database(dataBase).Collection(col)

    // InsertMany 메소드는 Context 타입과 함께 empty interface 요구
    delResult, err = collection.DeleteOne(ctx, query)

    return
}

// collection 내부로 여러 Document delete 를 수행하는 메소드
// delete 결과와 에러를 반환
func deleteMany(client *mongo.Client, ctx context.Context,
    dataBase, col string, query []interface{}) (delResult *mongo.DeleteResult, err error) {

    // Client.Database 메소드를 통해 작업하고자 하는 Database, Collection 선택
    collection := client.Database(dataBase).Collection(col)

    // InsertMany 메소드는 Context 타입과 함께 empty interface 요구
    delResult, err = collection.DeleteMany(ctx, query)

    return
}

func main() {

    // client, context, cancelFun, err 생성
    client, ctx, cancel, err := connect("mongodb://localhost:27017")

    if err != nil {
        panic(err)
    }

    // main 함수가 종료되면 모든 리소스 반환할 수 있도록 defer 통해 호출
    defer close(client, ctx, cancel)

    // delete 를 진행할 query
    query := bson.D {
        {"maths", bson.D{{"$gt", 60}}},
    }

    // arg: client, context, database name, collection name, query for delete
    // 삭제의 결과와 에러를 반환
    result, err := deleteOne(client, ctx, "gfg", "marks", query)
    if err != nil {
        panic(err)
    }

    fmt.Println("No.of rows affected by deleteOne()")
    fmt.Println(result.DeletedCount)

    // delete 를 진행할 querys
    var querys []interface{}
    querys = []interface{} {
        bson.D{
            {"science", bson.D{{"gt", 0}}},
            {"maths", bson.D{{"$gt", 10}}},
        },
    }

    // arg: client, context, database name, collection name, querys for delete
    // 삭제의 결과와 에러를 반환
    result, err = deleteMany(client, ctx, "gfg", "marks", querys)
    if err != nil {
        panic(err)
    }

    fmt.Println("No.of rows affected by deleteMany()")
    fmt.Println(result.DeletedCount)
}

 

4. 찾기


코드에서는 다음 순서로 작업을 진행합니다.

  1. mongoDB client 함수로 mongo.Client를 생성합니다. mongo.Client는 MongoDB와의 연결을 처리하게 됩니다.
  2. mongo.Client.Database는 데이터베이스에 대한 포인터를 반환합니다.
  3. 데이터베이스에 대한 포인터에는 작업을 진행할 collection을 찾기 위한 메소드 collection이 있습니다.
  4. 컬렉션은 데이터베이스를 쿼리하는 Find() 메서드를 제공합니다.
  5. 작업이 마무리되었다면 mongo.Client.Disconnect 를 사용하여 데이터베이스 연결을 닫습니다.
package main

import (
    "context"
    "fmt"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "time"
)

func close(client *mongo.Client, ctx context.Context, cancel context.CancelFunc) {
    defer cancel()

    defer func() {
        if err := client.Disconnect(ctx); err != nil {
            panic(err)
        }
    }()
}

// 연결을 생성하고, 관련 리소스를 반환하는 메소드
// mongo.Client: DB를 사용하는 Client
// context.Context: 문제가 발생하면 function call 차단하기 위해 활용
//        ex. timeout 발생시 생성한 context 전달하여 제어 가능
//        해당 코드에서는 데이터베이스 connection이 너무 길어지는 것을 방지
//        지정한 시간이 지난 후에 context에 다시 접근하려고 하는 경우
//        TimeOut에 따라서 다음의 오류 발생 -> "context deadline exceeded"
// context.CancelFunc: CancelFunc를 호출 시 자식과 이와 그 하위 자식들이 cancel, 자식들의 부모에 대한 참조가 모두 제거, 연결된 타이머 중지
func connect(url string) (client *mongo.Client, ctx context.Context, cancel context.CancelFunc, err error) {

    ctx, cancel = context.WithTimeout(context.Background(), 30 * time.Second)
    client, err = mongo.Connect(ctx, options.Client().ApplyURI(url))

    return
}

// find 를 활용하여 쿼리에 해당하는 mongo.Cursor 를 반환하는 메소드
// field: return 되는 필드를 제한하는 type interface
// query:
func query(client *mongo.Client, ctx context.Context,
    dataBase, col string, query, field interface{}) (result *mongo.Cursor, err error){

    collection := client.Database(dataBase).Collection(col)

    result, err = collection.Find(ctx, query, options.Find().SetProjection(field))
    return
}

func main() {
    client, ctx, cancel, err := connect("mongodb://localhost:27017")
    if err != nil {
        panic(err)
    }

    defer close(client, ctx, cancel)

    var filter, option interface{}

    // key 가 maths 이면서 value 가 70 이상인 필드가 존재하는 document 가 filter 에 담김
    filter = bson.D {
        {"maths", bson.D{{"$gt", 70}}},
    }

    // 모든 document 로부터 id field 를 제거
    option = bson.D{{"_id", 0}}

    // client, context 를 통해 query 메소드를 호출
    // mongo.cursor 와 error 를 반환
    cursor, err := query(client, ctx, "gtg", "marks", filter, option)
    if err != nil {
        panic(err)
    }

    var results []bson.D

    // mongo.cursor 로부터 bson 객체 읽어들임
    if err := cursor.All(ctx, &results); err != nil {
        panic(err)
    }

    // query 결과 출력
    fmt.Println("Query Result")
    for _, doc := range results {
        fmt.Println(doc)
    }
}

 

5. 업데이트


코드에서는 다음 순서로 작업을 진행합니다.

  1. mongoDB client 함수로 mongo.Client를 생성합니다. mongo.Client는 MongoDB와의 연결을 처리하게 됩니다.
  2. mongo.Client.Database는 데이터베이스에 대한 포인터를 반환합니다.
  3. 데이터베이스에 대한 포인터에는 작업을 진행할 collection을 찾기 위한 메소드 collection이 있습니다.
  4. collection 타입에는 문서를 삽입하기 위한 두 가지 방법을 제공합니다.
  5. Collection.InsertOne() 메서드를 통해서는 하나의 Document를 데이터베이스에 삽입할 수 있습니다.
  6. Collection.InsertMany() 메서드를 통해서는 Document의 리스트를 데이터베이스에 삽입할 수 있습니다.
  7. 삽입이 완료되었다면, mongo.Client.Disconnect를 통해 데이터베이스의 연결을 닫습니다.
package main

import (
    "context"
    "fmt"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "time"
)

// 리소스를 Close 하기 위한 메소드
// context close 와 client disconnect 처리
func close(client *mongo.Client, ctx context.Context, cancel context.CancelFunc) {

    defer cancel()
    defer func() {
        if err := client.Disconnect(ctx); err != nil {
            panic(err)
        }
    }()
}

// 연결을 생성하고, 관련 리소스를 반환하는 메소드
// mongo.Client: DB를 사용하는 Client
// context.Context: 문제가 발생하면 function call 차단하기 위해 활용
//    ex. timeout 발생시 생성한 context 전달하여 제어 가능
//    해당 코드에서는 데이터베이스 connection이 너무 길어지는 것을 방지
//    지정한 시간이 지난 후에 context에 다시 접근하려고 하는 경우
//    TimeOut에 따라서 다음의 오류 발생 -> "context deadline exceeded"
// context.CancelFunc: CancelFunc를 호출 시 자식과 이와 그 하위 자식들이 cancel, 자식들의 부모에 대한 참조가 모두 제거, 연결된 타이머 중지
func connect(url string)(client *mongo.Client, ctx context.Context, cancel context.CancelFunc, err error) {

    ctx, cancel = context.WithTimeout(context.Background(), 30 * time.Second)
    client, err = mongo.Connect(ctx, options.Client().ApplyURI(url))
    return client, ctx, cancel, err
}

// UpdateOne Document collection 내부로 단일 update 를 수행하는 메소드
// update 결과와 에러를 반환
func UpdateOne(client *mongo.Client, ctx context.Context,
    dataBase, col string, filter, update interface{}) (result *mongo.UpdateResult, err error) {

    // Client.Database 메소드를 통해 작업하고자 하는 Database, Collection 선택
    collection := client.Database(dataBase).Collection(col)

    // UpdateOne 메소드는 Context 타입과 함께 empty interface 요구
    result, err = collection.UpdateOne(ctx, filter, update)
    return
}

// UpdateMany Document collection 내부로 여러 update 를 수행하는 메소드
// update 결과와 에러를 반환
func UpdateMany (client *mongo.Client, ctx context.Context,
    database, col string, filter, update interface{}) (result *mongo.UpdateResult, err error) {

    // Client.Database 메소드를 통해 작업하고자 하는 Database, Collection 선택
    collection := client.Database(database).Collection(col)

    // UpdateMany 메소드는 Context 타입과 함께 empty interface 요구
    result, err = collection.UpdateMany(ctx, filter, update)
    return result, err
}

func main() {

    // client, context, cancelFun, err 생성
    client, ctx, cancel, err := connect("mongodb://localhost:27017")
    if err != nil {
        panic(err)
    }

    // main 함수가 종료되면 모든 리소스 반환할 수 있도록 defer 통해 호출
    defer close(client, ctx, cancel)

    // ---------------------------------------------------------------------------
    // 필터와 쿼리를 작성
    filter := bson.D {
        {"maths", bson.D{{"lt", 100}}},
    }
    update := bson.D {
        {"$set", bson.D {
            {"maths", 100},
        }},
    }

    // arg: client, context, database name, collection name, 업데이트될 doc interface
    // 업데이트의 결과와 에러를 반환
    UpdateOneResult, err := UpdateOne(client, ctx, "gfg", "marks", filter, update)

    if err != nil {
        panic(err)
    }

    // 업데이트가 완료되었다면 변경된만큼의 수 출력
    fmt.Println("update single document")
    fmt.Println(UpdateOneResult.ModifiedCount)

    // ---------------------------------------------------------------------------
    // 필터와 쿼리를 작성
    filter = bson.D{
        {"computer", bson.D{{"$lt", 100}}},
    }
    update = bson.D{
        {"$set", bson.D{
            {"computer", 100},
        }},
    }

    // arg: client, context, database name, collection name, 삽입될 doc interface slice
    // 삽입의 결과와 에러를 리턴
    // 삽입 중 하나라도 에러가 있을 경우 에러를 채워서 반환
    UpdatemanyResult, err := UpdateMany(client, ctx, "gfg", "marks", filter, update)
    if err != nil {
        panic(err)
    }

    // 업데이트가 완료되었다면 변경된만큼의 수 출력
    fmt.Println("update multiple document")
    fmt.Println(UpdatemanyResult.ModifiedCount)
}