MongoDB in golang

MongoDB Query

MongoDB

MongoDB๋Š” document ์ง€ํ–ฅ์ ์ธ NoSQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ด๋‹ค.

๋‹ค์–‘ํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ MongoDB๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ๊ทธ ํ™•์žฅ์„ฑ๊ณผ ๊ฐœ๋ฐœ์˜ ์šฉ์ด์„ฑ ๋•Œ๋ฌธ์ด๋‹ค.

Simple Query

๊ฐ„๋‹จํ•œ CRUD Query ์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด์ž.

ํ˜ผํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๊ณ , ๊ทธ ์˜ˆ์ œ๊ฐ€ ๋งค์šฐ ๋‹ค์–‘ํ•˜๋‹ค.

์ž์„ธํ•œ ๊ฒƒ์€ ๊ณต์‹ ๋ฌธ์„œ์ฐธ๊ณ ํ•˜์ž.

Find

bson.M ์„ ์‚ฌ์šฉํ•ด๋„ ๋˜๊ณ , map[string]interface{} ํ˜น์€ map[string]any ์™€ ๊ฐ™์ด ํ•„ํ„ฐ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

	ctx := context.TODO()
	collection.Find(ctx, bson.M{"name": "primrose"})
	collection.Find(ctx, map[string]interface{}{"name": "primrose"})
	collection.FindOne(ctx, bson.M{"name": "primrose"})
	collection.FindOne(ctx, map[string]interface{}{"name": "primrose"})

Insert

๊ตฌ์กฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋˜๊ณ , ๋‹จ์ˆœํ•œ document ํ˜•ํƒœ๋ผ๋ฉด bson.M ์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ๋‹ค.

	ctx = context.TODO()
	collection.InsertOne(ctx, bson.M{"name": "primrose"})
	collection.InsertMany(ctx, []interface{}{bson.M{"name": "primrose"}})

	type User struct {
		Name string `bson:"name"`
	}

	ctx = context.TODO()
	collection.InsertOne(ctx, User{Name: "primrose"})
	collection.InsertMany(ctx, []interface{}{User{Name: "primrose"}})

Update

MongoDB์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํฌ๊ฒŒ ๋‹จ์ผ ๋ฌธ์„œ ์—…๋ฐ์ดํŠธ(UpdateOne)์™€ ์—ฌ๋Ÿฌ ๋ฌธ์„œ ๋™์‹œ ์—…๋ฐ์ดํŠธ(UpdateMany), ๊ทธ๋ฆฌ๊ณ  ๋Œ€๋Ÿ‰ ์—…๋ฐ์ดํŠธ(BulkWrite)๋ฅผ ํฌํ•จํ•œ๋‹ค.

๊ฐ๊ฐ์˜ ์‚ฌ์šฉ ์˜ˆ๋ฅผ ์‚ดํŽด๋ณด๋ฉฐ, ํŠน์ • ์ƒํ™ฉ์—์„œ ์–ด๋–ป๊ฒŒ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด์ž.

	ctx = context.TODO()
	// ๋‹จ์ผ ๋ฌธ์„œ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ๋•Œ๋Š” UpdateOne ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. 
	// ์ด ๋ฉ”์„œ๋“œ๋Š” ์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ํ•„ํ„ฐ ์กฐ๊ฑด์„, ๋‘ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์—…๋ฐ์ดํŠธํ•  ๋‚ด์šฉ์„ ๋ฐ›๋Š”๋‹ค.
	collection.UpdateOne(ctx, bson.M{"name": "primrose"}, bson.M{"$set": bson.M{"name": "primrose"}})

	filter := bson.M{"name": "primrose"}
	update := bson.M{"$set": bson.M{"name": "primrose"}}
	ctx = context.TODO()
	collection.UpdateOne(ctx, filter, update)
	// ์—ฌ๋Ÿฌ ๋ฌธ์„œ๋ฅผ ๋™์‹œ์— ์—…๋ฐ์ดํŠธ ํ•  ๋•Œ๋Š” UpdateMany ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. 
	// ์ด ๋ฐฉ๋ฒ•์€ ์ฃผ๋กœ ๋™์ผํ•œ ํ•„ํ„ฐ ์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฌธ์„œ์— ๋™์ผํ•œ ๋ณ€๊ฒฝ์„ ์ ์šฉํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.
	collection.UpdateMany(ctx, filter, update)

UpdateMany ๋Š” ๋™์ผํ•œ ํ•„ํ„ฐ๋กœ ์—ฌ๋Ÿฌ ๊ฐœ์˜ document ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ 500๊ฐœ์˜ ๋ฌธ์„œ๋ฅผ ๊ฐ๊ฐ ์กฐ๊ฑด์— ๋งž๊ฒŒ ์—…๋ฐ์ดํŠธ ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์–ด๋–จ๊นŒ?

500 ๋ฒˆ์˜ UpdateOne ๋ณด๋‹ค๋Š”, BulkWrite ๋ฅผ ์ถ”์ฒœํ•œ๋‹ค.

models := []mongo.WriteModel{
	mongo.NewUpdateOneModel().SetFilter(bson.M{"name": "primrose"}).SetUpdate(bson.M{"$set": bson.M{"name": "rosie"}}),
	mongo.NewUpdateOneModel().SetFilter(bson.M{"name": "daisy"}).SetUpdate(bson.M{"$set": bson.M{"name": "sunflower"}}),
	// ์ถ”๊ฐ€์ ์ธ ์—…๋ฐ์ดํŠธ ๋ชจ๋ธ์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค.
}

results, err := collection.BulkWrite(ctx, models)
if err != nil {
	log.Fatal(err)
}
fmt.Printf("Operations completed: %v\n", results.ModifiedCount)

์ด๋ ‡๊ฒŒ ๋Œ€๋Ÿ‰ ์—…๋ฐ์ดํŠธ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ๋Š” ๊ฐ ๋ฌธ์„œ์— ์ ํ•ฉํ•œ ํ•„ํ„ฐ์™€ ์—…๋ฐ์ดํŠธ ์กฐ๊ฑด์„ ๋ช…์‹œํ•ด์•ผ ํ•˜๋ฉฐ, ์ด๋Š” ๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ๊ณผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ถ€ํ•˜๋ฅผ ์ค„์ด๋Š” ๋ฐ ๋„์›€์ด ๋œ๋‹ค.

ํŠน์ˆ˜ ์—…๋ฐ์ดํŠธ ์˜ต์…˜ ํ™œ์šฉ

  • $set: ๋ฌธ์„œ์˜ ํŠน์ • ํ•„๋“œ๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ ํ•œ๋‹ค.

  • $setOnInsert: ๋ฌธ์„œ๊ฐ€ ์‚ฝ์ž…๋  ๋•Œ๋งŒ ํŠน์ • ํ•„๋“œ๋ฅผ ์„ค์ •ํ•œ๋‹ค.

์ด ์˜ต์…˜๋“ค์„ ํ™œ์šฉํ•˜์—ฌ, ์กฐ๊ฑด์— ๋งž๋Š” ๋ฌธ์„œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์„ ๋•Œ ์‚ฝ์ž… ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ฉด์„œ ํŠน์ • ํ•„๋“œ๋ฅผ ์„ค์ •ํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด upsert ์˜ต์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค.

updateOptions := options.Update().SetUpsert(true)
updateResult, err := collection.UpdateOne(ctx, filter, update, updateOptions)
if err != nil {
	log.Fatal(err)
}
if updateResult.UpsertedCount > 0 {
	fmt.Printf("One document was upserted.\n")
}

Delete

MongoDB์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•˜๋Š” ์—ฐ์‚ฐ์€ ์ฃผ๋กœ DeleteOne๊ณผ DeleteMany ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ˆ˜ํ–‰๋œ๋‹ค.

๊ฐ๊ฐ์˜ ๋ฉ”์„œ๋“œ๋Š” ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ฌธ์„œ๋ฅผ ์‚ญ์ œํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

๋‹จ์ผ ๋ฌธ์„œ ์‚ญ์ œ: DeleteOne

DeleteOne ๋ฉ”์„œ๋“œ๋Š” ์ฃผ์–ด์ง„ ํ•„ํ„ฐ์— ๋งž๋Š” ์ฒซ ๋ฒˆ์งธ ๋ฌธ์„œ ํ•˜๋‚˜๋งŒ์„ ์‚ญ์ œํ•œ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ํŠน์ • ๋„ํ๋จผํŠธ๋ฅผ ์ •ํ™•ํžˆ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋ฉฐ, ํ•„ํ„ฐ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์œ ๋‹ˆํฌํ•œ ํ•„๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค์ •๋œ๋‹ค.

ctx := context.TODO()
filter := bson.M{"name": "rosie"}
result, err := collection.DeleteOne(ctx, filter)
if err != nil {
	log.Fatal(err)
}
fmt.Printf("Deleted %v documents.\n", result.DeletedCount)

์—ฌ๋Ÿฌ ๋ฌธ์„œ ์‚ญ์ œ: DeleteMany

DeleteMany ๋ฉ”์„œ๋“œ๋Š” ์ฃผ์–ด์ง„ ํ•„ํ„ฐ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ชจ๋“  ๋ฌธ์„œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ํŠน์ • ์กฐ๊ฑด์„ ๊ณต์œ ํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฌธ์„œ๋ฅผ ํ•œ ๋ฒˆ์— ์‚ญ์ œํ•˜๊ณ ์ž ํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.

filter := bson.M{"status": "inactive"}
deleteResult, err := collection.DeleteMany(ctx, filter)
if err != nil {
	log.Fatal(err)
}
fmt.Printf("Deleted %v documents.\n", deleteResult.DeletedCount)

Aggregate

Aggregate ์—ฐ์‚ฐ์€ MongoDB์˜ ๊ฐ•๋ ฅํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๋กœ, ์—ฌ๋Ÿฌ ๋‹จ๊ณ„์˜ ํŒŒ์ดํ”„๋ผ์ธ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€ํ™˜ํ•˜๊ณ  ์š”์•ฝํ•˜๋Š” ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ธฐ๋ณธ Aggregate ์‚ฌ์šฉ ์˜ˆ

๋‹ค์Œ์€ ๊ฐ„๋‹จํ•œ Aggregate ์˜ˆ์ œ๋กœ, ์‚ฌ์šฉ์ž์˜ ๋‚˜์ด์— ๋”ฐ๋ฅธ ๊ทธ๋ฃน์„ ๋งŒ๋“ค๊ณ  ๊ฐ ๊ทธ๋ฃน์˜ ํ‰๊ท  ์ ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ์ฟผ๋ฆฌ์ด๋‹ค.

pipeline := mongo.Pipeline{
	{{"$match", bson.D{{"age", bson.D{{"$gte", 18}}}}}},
	{{"$group", bson.D{{"_id", "$age"}, {"averageScore", bson.D{{"$avg", "$score"}}}}}},
}

ctx := context.TODO()
cursor, err := collection.Aggregate(ctx, pipeline)
if err != nil {
	log.Fatal(err)
}

var results []bson.M
if err = cursor.All(ctx, &results); err != nil {
	log.Fatal(err)
}
fmt.Println("Age Groups and Average Scores:")
for _, result := range results {
	fmt.Println(result)
}

Aggregate vs. Find

  • Find๋Š” ๊ฐ„๋‹จํ•œ ๋ฌธ์„œ ๊ฒ€์ƒ‰์— ์‚ฌ์šฉ๋˜๋ฉฐ, ํŠน์ • ์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋Š” ๋ฌธ์„œ๋“ค์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

  • Aggregate๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ์ž‘ํ•˜๊ณ  ์š”์•ฝํ•˜์—ฌ ๋” ๋ณต์žกํ•œ ์ฟผ๋ฆฌ์™€ ๋ฐ์ดํ„ฐ ๋ถ„์„์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฌธ์„œ๋ฅผ ๊ทธ๋ฃนํ™”ํ•˜๊ณ  ๊ฐ ๊ทธ๋ฃน์— ๋Œ€ํ•ด ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

Aggregate ์—ฐ์‚ฐ์€ Find ์—ฐ์‚ฐ๋ณด๋‹ค ํ›จ์”ฌ ๋” ์œ ์—ฐํ•˜๊ณ  ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๋” ๋งŽ์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์†Œ๋ชจํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์‚ฌ์šฉ ์‹œ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์ ์ ˆํžˆ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

BSON

MongoDB์˜ ๋ฐ์ดํ„ฐ ํ˜•์‹์ธ BSON(Binary JSON)์€ JSON๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ, ์ด์ง„ ํ˜•์‹์œผ๋กœ ํ‘œํ˜„๋˜๋ฉฐ ํ›จ์”ฌ ๋” ๋งŽ์€ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์ง€์›ํ•œ๋‹ค.

Golang์—์„œ๋Š” mongo-go-driver ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด bson.E, bson.M, bson.A, bson.D ๋“ฑ ๋‹ค์–‘ํ•œ BSON ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋“ค ๊ฐ๊ฐ์˜ ํƒ€์ž…๊ณผ ์‚ฌ์šฉ ์‹œ์˜ ํŠน์ง•์„ ์ดํ•ดํ•˜๋ฉด, MongoDB ๋ฐ์ดํ„ฐ ์ž‘์—…์„ ๋ณด๋‹ค ํšจ์œจ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

BSON ํƒ€์ž…๋“ค

  1. bson.M: ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ BSON ํƒ€์ž…์œผ๋กœ, map[string]interface{} ํƒ€์ž…์ด๋‹ค. ๋ฌธ์„œ์˜ ํ•„๋“œ๊ฐ€ ๋ฌธ์ž์—ด ํ‚ค์™€ ๊ด€๋ จ๋œ ๊ฐ’์œผ๋กœ ๊ตฌ์„ฑ๋˜๋ฉฐ, ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ผ๋ฐ˜์ ์ธ CRUD ์ž‘์—…์— ๋„๋ฆฌ ์‚ฌ์šฉ๋œ๋‹ค.

    // type M map[string]interface{}
    doc := bson.M{"name": "John", "age": 30}
  2. bson.D: ๋ฌธ์„œ์˜ ํ•„๋“œ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ํƒ€์ž…์œผ๋กœ, []bson.E์˜ ๋ณ„์นญ์ด๋‹ค. ์ด ํƒ€์ž…์€ ์ฟผ๋ฆฌ์™€ ์ธ๋ฑ์Šค ์ƒ์„ฑ ์‹œ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•œ ๊ฒฝ์šฐ ์œ ์šฉํ•˜๋‹ค.

    // type D []E
    // type E struct {
    //	Key   string
    //	Value interface{}
    // }
    doc := bson.D{{"name", "John"}, {"age", 30}}
  3. bson.A: ๋ฐฐ์—ด์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, []interface{}์™€ ์œ ์‚ฌํ•˜๋‹ค. BSON ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•  ๋•Œ ์‚ฌ์šฉ๋˜๊ณ , ์—ฌ๋Ÿฌ ๊ฐ’์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ €์žฅํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.

    // type A []interface{}
    arr := bson.A{"apple", "banana", "cherry"}
  4. bson.E: ๋ฌธ์„œ์˜ ํ•œ ํ•„๋“œ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํƒ€์ž…์œผ๋กœ, ํ‚ค์™€ ๊ฐ’์˜ ์Œ์„ ์ €์žฅํ•œ๋‹ค. ์ฃผ๋กœ bson.D ๋‚ด์—์„œ ์‚ฌ์šฉ๋œ๋‹ค.

    // type E struct {
    //	Key   string
    //	Value interface{}
    // }
    element := bson.E{Key: "name", Value: "John"}

๊ฐ ํƒ€์ž…์˜ ์‚ฌ์šฉ ์‹œ์ ๊ณผ ํŠน์ง•

  • bson.M์€ ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ธ ๋ฌธ์„œ ์ž‘์—…์— ์ ํ•ฉํ•˜๋ฉฐ, ํ•„๋“œ ์ˆœ์„œ๋ฅผ ๊ณ ๋ คํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์œ ๋ฆฌํ•˜๋‹ค. CRUD ์ž‘์—…์—์„œ์˜ ๋ฐ์ดํ„ฐ ํ‘œํ˜„๊ณผ ๊ฐ™์ด ๋ณต์žกํ•˜์ง€ ์•Š์€ ์ฟผ๋ฆฌ์— ์ฃผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

  • bson.D๋Š” ํ•„๋“œ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•œ ๊ฒฝ์šฐ, ์˜ˆ๋ฅผ ๋“ค์–ด ์ธ๋ฑ์Šค ์ƒ์„ฑ์ด๋‚˜ ๋ณตํ•ฉ ์ฟผ๋ฆฌ์—์„œ ํ•„๋“œ ์ˆœ์„œ์— ์˜์กดํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค. ์ˆœ์„œ๊ฐ€ ๊ฒฐ๊ณผ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ์ž‘์—…์—์„œ ๋งค์šฐ ์œ ์šฉํ•˜๋‹ค.

  • bson.A๋Š” ๋ฐฐ์—ด ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ํ•„์š”ํ•˜๋ฉฐ, MongoDB์—์„œ ๋ฐฐ์—ด ํ•„๋“œ๋ฅผ ์ฟผ๋ฆฌํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

  • bson.E๋Š” ๋ณดํ†ต bson.D๋ฅผ ๊ตฌ์„ฑํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋ฉฐ, ๊ฐœ๋ณ„ ํ•„๋“œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ‘œํ˜„ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

์‚ฌ์šฉ ์˜ˆ์ œ

MongoDB์—์„œ ์กฐ๊ฑด์— ๋”ฐ๋ผ ํ•„๋“œ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•œ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ bson.D์˜ ์‚ฌ์šฉ ์˜ˆ๋ฅผ ๋“ค ์ˆ˜ ์žˆ๋‹ค.

filter := bson.D{{"age", bson.D{{"$gt", 30}}}, {"name", "John"}}
update := bson.D{{"$set", bson.D{{"age", 32}}}}
result, err := collection.UpdateOne(ctx, filter, update)
if err != nil {
	log.Fatal(err)
}

์ด ์˜ˆ์ œ์—์„œ๋Š” bson.D๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•„ํ„ฐ์™€ ์—…๋ฐ์ดํŠธ ๋ฌธ์„œ์˜ ํ•„๋“œ ์ˆœ์„œ๋ฅผ ์ •ํ™•ํžˆ ์ œ์–ดํ•œ๋‹ค.

์ด๋Š” MongoDB์˜ ์ฟผ๋ฆฌ ํ”Œ๋ž˜๋„ˆ๊ฐ€ ์ธ๋ฑ์Šค๋ฅผ ๋ณด๋‹ค ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•˜๊ฒŒ ํ•ด ์ฃผ์–ด ์„ฑ๋Šฅ ๊ฐœ์„ ์„ ๋„๋ชจํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ฐ๊ฐ์˜ BSON ํƒ€์ž…๋“ค์„ ์ดํ•ดํ•˜๊ณ  ์ ์ ˆํ•˜๊ฒŒ ํ™œ์šฉํ•˜๋ฉด, MongoDB ์—์„œ์˜ ๋ฐ์ดํ„ฐ ์ž‘์—…์ด ๋ณด๋‹ค ์œ ์—ฐํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ์ด๋ฃจ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

Index

MongoDB์—์„œ ์ธ๋ฑ์Šค๋Š” ๋ฐ์ดํ„ฐ ๊ฒ€์ƒ‰ ์†๋„๋ฅผ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ์ค‘์š”ํ•œ ๋„๊ตฌ์ด๋‹ค.

์ธ๋ฑ์Šค๋ฅผ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•˜๋ฉด, ๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ์…‹์—์„œ๋„ ๋น ๋ฅด๊ฒŒ ์ •๋ณด๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ฟผ๋ฆฌ ์„ฑ๋Šฅ์„ ํฌ๊ฒŒ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ์„น์…˜์—์„œ๋Š” MongoDB์— ์ธ๋ฑ์Šค๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์ธ๋ฑ์‹ฑ๋œ ์ฟผ๋ฆฌ๋ฅผ Find ๋ฐ Aggregate ์ž‘์—…์— ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

์ธ๋ฑ์Šค ์ ์šฉ ๋ฐฉ๋ฒ•

MongoDB์—์„œ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•์€ createIndex ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์ด ๋ฉ”์„œ๋“œ๋Š” ์ปฌ๋ ‰์…˜์— ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉฐ, ์—ฌ๋Ÿฌ ์˜ต์…˜์„ ์„ค์ •ํ•˜์—ฌ ๋‹ค์–‘ํ•œ ์œ ํ˜•์˜ ์ธ๋ฑ์Šค๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ์‹œ: ๋‹จ์ผ ํ•„๋“œ ์ธ๋ฑ์Šค ์ƒ์„ฑ

ctx := context.TODO()
collection := client.Database("testdb").Collection("documents")

indexModel := mongo.IndexModel{
    Keys: bson.M{"name": 1}, // 1์€ ์˜ค๋ฆ„์ฐจ์ˆœ ์ธ๋ฑ์‹ฑ์„ ์˜๋ฏธ
}
_, err := collection.Indexes().CreateOne(ctx, indexModel)
if err != nil {
    log.Fatal(err)
}

์˜ˆ์‹œ: ๋ณตํ•ฉ ์ธ๋ฑ์Šค ์ƒ์„ฑ

indexModel = mongo.IndexModel{
    Keys: bson.D{
        {Key: "lastname", Value: 1},
        {Key: "firstname", Value: 1},
    },
    Options: options.Index().SetUnique(true), // ์ค‘๋ณต์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š” ์œ ๋‹ˆํฌ ์ธ๋ฑ์Šค
}
_, err = collection.Indexes().CreateOne(ctx, indexModel)
if err != nil {
    log.Fatal(err)
}

์ธ๋ฑ์‹ฑ๋œ ์ฟผ๋ฆฌ ์‚ฌ์šฉ

์ธ๋ฑ์Šค๋Š” ์ฟผ๋ฆฌ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ํ›‘๋Š” ๋Œ€์‹ , ํšจ์œจ์ ์œผ๋กœ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š”๋‹ค.

Find ๋ฐ Aggregate ํ•จ์ˆ˜์— ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

Find ์ฟผ๋ฆฌ์—์„œ ์ธ๋ฑ์Šค ์‚ฌ์šฉ

์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Find ์ฟผ๋ฆฌ์˜ ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, "name" ํ•„๋“œ์— ์ธ๋ฑ์Šค๊ฐ€ ์žˆ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

filter := bson.M{"name": "John Doe"}
cursor, err := collection.Find(ctx, filter)
if err != nil {
    log.Fatal(err)
}

Aggregate ์ฟผ๋ฆฌ์—์„œ ์ธ๋ฑ์Šค ์‚ฌ์šฉ

Aggregate ์ฟผ๋ฆฌ์—์„œ๋„ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ธ๋ฑ์Šค๋Š” ํŠนํžˆ $match์™€ $sort ๋‹จ๊ณ„์—์„œ ์œ ์šฉํ•˜๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, "age" ํ•„๋“œ์— ์ธ๋ฑ์Šค๊ฐ€ ์žˆ๊ณ , ๋‚˜์ด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ ์ธ๋ฑ์Šค๊ฐ€ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•œ๋‹ค.

pipeline := mongo.Pipeline{
    {{"$match", bson.D{{"age", bson.D{{"$gte", 30}}}}}},
    {{"$sort", bson.D{{"age", 1}}}},
}
cursor, err := collection.Aggregate(ctx, pipeline)
if err != nil {
    log.Fatal(err)
}

MongoDB Query Plan

MongoDB์˜ ์ฟผ๋ฆฌ ํ”Œ๋žœ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์–ด๋–ป๊ฒŒ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด๋‹ค.

์ด ํ”Œ๋žœ์€ ์ตœ์ ์˜ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๊ฐ€๋Šฅํ•œ ๊ฒฝ๋กœ ์ค‘์—์„œ ์ตœ์„ ์˜ ์„ ํƒ์„ ํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ๋‹ค.

์ฟผ๋ฆฌ ํ”Œ๋žœ์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ฑ๋Šฅ ์ตœ์ ํ™”์— ์ค‘์š”ํ•˜๋ฉฐ, MongoDB๋Š” ์ด๋ฅผ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๋‚ด๋ถ€ ๋ฉ”์ปค๋‹ˆ์ฆ˜๊ณผ ์ตœ์ ํ™” ๋„๊ตฌ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

์ฟผ๋ฆฌ ํ”Œ๋ž˜๋„ˆ์˜ ์ž‘๋™ ๋ฐฉ์‹

MongoDB๋Š” ์ฟผ๋ฆฌ๋ฅผ ๋ฐ›์œผ๋ฉด ๋จผ์ € ์ฟผ๋ฆฌ ํ”Œ๋ž˜๋„ˆ๋ฅผ ํ†ตํ•ด ์‹คํ–‰ ๊ณ„ํš์„ ๋งŒ๋“ ๋‹ค. ์ฟผ๋ฆฌ ํ”Œ๋ž˜๋„ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹จ๊ณ„๋กœ ์ž‘๋™ํ•œ๋‹ค:

  1. ์ฟผ๋ฆฌ ๋ถ„์„: MongoDB๋Š” ์ฃผ์–ด์ง„ ์ฟผ๋ฆฌ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ธ๋ฑ์Šค๋ฅผ ํ‰๊ฐ€ํ•œ๋‹ค. ์ด๋•Œ ์ฟผ๋ฆฌ์— ์‚ฌ์šฉ๋œ ์กฐ๊ฑด๊ณผ ํ•„๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ธ๋ฑ์Šค์˜ ์œ ์šฉ์„ฑ์„ ํŒ๋‹จํ•œ๋‹ค.

  2. ํ”Œ๋žœ ํ›„๋ณด ์ƒ์„ฑ: ์—ฌ๋Ÿฌ ์ธ๋ฑ์Šค ์ค‘์—์„œ ์ ํ•ฉํ•œ ํ›„๋ณด๋ฅผ ์„ ์ •ํ•˜์—ฌ ๊ฐ€๋Šฅํ•œ ์‹คํ–‰ ๊ณ„ํš์„ ๋งŒ๋“ ๋‹ค. ์ด ๊ณ„ํš์€ ์ธ๋ฑ์Šค ์Šค์บ”, ์ปฌ๋ ‰์…˜ ์Šค์บ” ๋“ฑ ๋‹ค์–‘ํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค.

  3. ํ”Œ๋žœ ํ‰๊ฐ€: ์ƒ์„ฑ๋œ ํ›„๋ณด๋“ค ์ค‘์—์„œ ์ตœ์ ์˜ ์„ฑ๋Šฅ์„ ๋ณด์ผ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๋Š” ํ”Œ๋žœ์„ ์„ ํƒํ•˜๊ธฐ ์œ„ํ•ด, MongoDB๋Š” ๊ฐ ํ”Œ๋žœ์„ ์ผ์ • ์‹œ๊ฐ„ ๋™์•ˆ ์‹คํ–‰ํ•ด ๋ณธ๋‹ค(์ด๋ฅผ ํ”Œ๋žœ ์บ์‹ฑ์ด๋ผ ํ•จ). ์ด ๊ณผ์ •์—์„œ ์‹ค์ œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ฟผ๋ฆฌ ์‹คํ–‰ ์‹œ๊ฐ„๊ณผ ์ž์› ์‚ฌ์šฉ๋Ÿ‰์„ ํ‰๊ฐ€ํ•œ๋‹ค.

  4. ์ตœ์ข… ํ”Œ๋žœ ์„ ํƒ: ๊ฐ€์žฅ ํšจ์œจ์ ์ธ ํ”Œ๋žœ์ด ์„ ํƒ๋˜์–ด ์ฟผ๋ฆฌ๊ฐ€ ๊ทธ์— ๋”ฐ๋ผ ์‹คํ–‰๋œ๋‹ค. ํ•œ ๋ฒˆ ์„ ํƒ๋œ ํ”Œ๋žœ์€ ์ผ์ • ๊ธฐ๊ฐ„ ๋™์•ˆ ์บ์‹œ๋˜์–ด, ๋™์ผํ•˜๊ฑฐ๋‚˜ ์œ ์‚ฌํ•œ ์ฟผ๋ฆฌ๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋  ๋•Œ ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฟผ๋ฆฌ ํ”Œ๋žœ์˜ ์‹คํ–‰ ๋ฐ ์ตœ์ ํ™”

์ฟผ๋ฆฌ ์‹คํ–‰ ๊ณ„ํš ํ™•์ธ

MongoDB์—์„œ๋Š” explain() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ์ฟผ๋ฆฌ์˜ ์‹คํ–‰ ๊ณ„ํš์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ด ๋ฉ”์†Œ๋“œ๋Š” ์ฟผ๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ์‹คํ–‰๋ ์ง€, ์–ด๋–ค ์ธ๋ฑ์Šค๊ฐ€ ์‚ฌ์šฉ๋˜๋Š”์ง€ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

db.collection.find({age: {$gt: 30}}).explain("executionStats")

์ด ๋ช…๋ น์€ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋ฐฉ์‹๊ณผ ๊ด€๋ จ๋œ ํ†ต๊ณ„์™€ ํ•จ๊ป˜ ์‹คํ–‰ ๊ณ„ํš์˜ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ด ์ •๋ณด๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๋Š” ์ฟผ๋ฆฌ ์„ฑ๋Šฅ์˜ ๋ณ‘๋ชฉ ํ˜„์ƒ์„ ์‹๋ณ„ํ•˜๊ณ  ํ•„์š”ํ•œ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ฟผ๋ฆฌ ์ž์ฒด๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฟผ๋ฆฌ ์ตœ์ ํ™”

์ฟผ๋ฆฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์ธ๋ฑ์Šค๋ฅผ ์กฐ์ •ํ•˜๊ฑฐ๋‚˜ ์ฟผ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„, MongoDB๋Š” ์ฟผ๋ฆฌ ํŒจํ„ด์„ ํ•™์Šตํ•˜์—ฌ ๋ฐ˜๋ณต์ ์ธ ์ฟผ๋ฆฌ์— ๋Œ€ํ•ด ๋” ๋น ๋ฅด๊ฒŒ ์‘๋‹ตํ•  ์ˆ˜ ์žˆ๋„๋ก ํ”Œ๋žœ์„ ์กฐ์ •ํ•œ๋‹ค.

์ด๋Ÿฌํ•œ ๋™์  ์ตœ์ ํ™”๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ „๋ฐ˜์ ์ธ ํšจ์œจ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

Options

MongoDB์˜ Golang ๋“œ๋ผ์ด๋ฒ„์—์„œ options ํŒจํ‚ค์ง€๋Š” ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—… ์„ค์ •์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ค€๋‹ค.

์ด ์ค‘ Projection์„ ํ†ตํ•ด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์—์„œ ํŠน์ • ํ•„๋“œ๋งŒ ์ถ”์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ค‘์ ์ ์œผ๋กœ ๋‹ค๋ฃฌ๋‹ค.

Projection

Projection์€ ๊ฒ€์ƒ‰๋œ ๋ฌธ์„œ์—์„œ ํŠน์ • ํ•„๋“œ๋งŒ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋„คํŠธ์›Œํฌ ์ „์†ก ๋ฐ์ดํ„ฐ๋Ÿ‰์„ ์ค„์ด๊ณ , ์ฒ˜๋ฆฌ ์†๋„๋ฅผ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ์—์„œ๋Š” name ํ•„๋“œ๊ฐ€ "primrose"์ธ ๋ฌธ์„œ์—์„œ email ํ•„๋“œ๋งŒ ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค€๋‹ค.

ctx := context.TODO()
collection := client.Database("your_database").Collection("your_collection")

// Find๋ฅผ ์‚ฌ์šฉํ•œ Projection
opts := options.Find().SetProjection(bson.M{"email": 1, "_id": 0})
cursor, err := collection.Find(ctx, bson.M{"name": "primrose"}, opts)
if err != nil {
	log.Fatal(err)
}
defer cursor.Close(ctx)

// FindOne์„ ์‚ฌ์šฉํ•œ Projection
optsOne := options.FindOne().SetProjection(bson.M{"email": 1, "_id": 0})
result := collection.FindOne(ctx, bson.M{"name": "primrose"}, optsOne)
if err := result.Err(); err != nil {
	log.Fatal(err)
}

var user bson.M
if err := result.Decode(&user); err != nil {
	log.Fatal(err)
}

Registry

Registry๋Š” BSON ํƒ€์ž…๊ณผ Go ํƒ€์ž… ๊ฐ„์˜ ๋ณ€ํ™˜์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

ํŠนํžˆ, primitive.Decimal128 ํƒ€์ž…์„ Go์˜ BigInt๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ปค์Šคํ…€ ์ฝ”๋ฑ์„ ๋“ฑ๋กํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณธ๋‹ค.

bsoncodec

bsoncodec๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ MongoDB์˜ Decimal128 ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ Go์˜ big.Int๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์Œ์€ Decimal128 ํƒ€์ž…์„ BigInt๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ปค์Šคํ…€ ์ฝ”๋ฑ์„ ๊ตฌํ˜„ํ•˜๊ณ , ์ด๋ฅผ Registry์— ๋“ฑ๋กํ•˜๋Š” ๊ณผ์ •์„ ๋ณด์—ฌ์ค€๋‹ค.

์˜ˆ์‹œ๊ฐ€ BigInt ์ผ ๋ฟ์ด๊ณ , ๋‹ค๋ฅธ ํ˜•ํƒœ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ฐ์ž ์‘์šฉํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ข‹์€ document ๋ฅผ ๋””์ž์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

type BigIntCodec struct{}

func (c *BigIntCodec) DecodeValue(decodeContext bsoncodec.DecodeContext, reader bsonrw.ValueReader, value reflect.Value) error {
	decimal128, err := reader.ReadDecimal128()
	if err != nil {
		return err
	}
	bi, ok := new(big.Int).SetString(decimal128.String(), 10)
	if !ok {
		return fmt.Errorf("could not convert Decimal128 to BigInt")
	}
	value.Set(reflect.ValueOf(bi))
	return nil
}

func (c *BigIntCodec) EncodeValue(encodeContext bsoncodec.EncodeContext, writer bsonrw.ValueWriter, value reflect.Value) error {
	if !value.IsValid() || value.Type() != reflect.TypeOf((*big.Int)(nil)) {
		return bsoncodec.ValueEncoderError{Name: "BigIntCodec.EncodeValue", Types: []reflect.Type{reflect.TypeOf((*big.Int)(nil))}, Received: value}
	}
	decimal128, err := primitive.ParseDecimal128(value.Interface().(*big.Int).String())
	if err != nil {
		return err
	}
	return writer.WriteDecimal128(decimal128)
}

๋จผ์ € ์œ„ BigInt Codec ์„ ๊ตฌํ˜„ํ–ˆ๋‹ค.

๋‹จ์ˆœํžˆ Decimal128 ์„ ์ฝ์–ด์„œ BigInt ๋กœ ๋ณ€๊ฒฝํ•˜๋„๋ก ํ–ˆ๋‹ค.

bigIntCodec := &BigIntCodec{}
opts := bson.NewRegistry()
opts.RegisterTypeEncoder(reflect.TypeOf((*big.Int)(nil)), bigIntCodec)
opts.RegisterTypeDecoder(reflect.TypeOf((*big.Int)(nil)), bigIntCodec)

collection := client.Database("test").Collection("test", options.Collection().
    SetRegistry(opts),
)

์ปฌ๋ ‰์…˜์— ์—ฐ๊ฒฐํ•  ๋•Œ ์œ„์™€๊ฐ™์ด ์˜ต์…˜์„ ์ฃผ๋ฉด ๋œ๋‹ค.

type BigIntValue struct {
	Value *big.Int
}

if _, err = collection.InsertOne(ctx, BigIntValue{Value: big.NewInt(1234567890123456789)}); err != nil {
	panic(err)
}

var result BigIntValue
if err = collection.FindOne(ctx, bson.M{"value": big.NewInt(1234567890123456789)}).Decode(&result); err != nil {
	panic(err)
}

fmt.Println(result)
// {1234567890123456789}

Last updated