Skip to content

MongoDB

MongoDB هي قاعدة بيانات وثائقية، وحدتها الأساسية للبيانات هي الوثيقة، وتنسيق التخزين هو BSON (Binary JSON) وهو هيكل مشابه لـ JSON، حيث يتيح الهيكل المرن تخزين أنواع مختلفة من البيانات، مما يجعلها أكثر مرونة من قواعد البيانات العلائقية، كما تستخدم JavaScript كلغة برمجة نصية يمكن من خلالها إتمام العمليات المركبة. تقدم هذه المقالة كيفية استخدام مشغل MongoDB الرسمي في Go للتعامل مع قاعدة بيانات mongodb، وهي ليست درسًا تعليميًا عن mongodb، فإذا لم تكن لديك خلفية عن mongo، يرجى تعلمها بنفسك أولاً.

توثيق mongodb: Introduction to MongoDB — MongoDB Manual

المشغل

المكتبات الخاصة بـ mongodb في go قليلة نسبيًا، وفي وقت مبكر كانت هناك بعض المكتبات التي ي维护ها المجتمع، لكنها توقفت عن الصيانة لاحقًا، لكن مشغل mongo الرسمي كافٍ تمامًا للاستخدام.

المستودع مفتوح المصدر: mongodb/mongo-go-driver: The Official Golang driver for MongoDB (github.com)

عنوان الوثائق: mongodb/mongo-go-driver: The Official Golang driver for MongoDB (github.com)

التثبيت

لتحميل التبعية استخدم العنوان التالي.

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

الاتصال

فيما يلي مثال بسيط لإنشاء اتصال بين عميل mongo والخادم.

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"
   "log"
)

func main() {
   ctx := context.Background()
   // استخدام URI لإنشاء الاتصال
   client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://admin:123456@192.168.48.138:27017/"))
   if err != nil {
      log.Panicln(err)
   }
   // إغلاق الاتصال
   defer client.Disconnect(ctx)
   // اختبار ping للتحقق من صلاحية الاتصال
   fmt.Println(client.Ping(ctx, readpref.Primary()))
}

bson

يستخدم mongodb الأنواع التالية في go لتحويل وثائق قاعدة البيانات، الموجودة في bson/bson.go

go
// تمثيل مرتب لوثيقة BSON
type D = primitive.D

// زوج من المفتاح والقيمة، الوحدة الأساسية للتمثيل المرتب لوثيقة BSON
type E = primitive.E

// تمثيل غير مرتب لوثيقة BSON
type M = primitive.M

// تمثيل مرتب لمصفوفة BSON
type A = primitive.A

أنواعها الفعلية كالتالي

go
// تمثيل مرتب لوثيقة BSON
type D []E

// زوج من المفتاح والقيمة، الوحدة الأساسية للتمثيل المرتب لوثيقة BSON
type E struct {
  Key   string
  Value interface{}
}

// تمثيل غير مرتب لوثيقة BSON
type M map[string]interface{}

// تمثيل مرتب لمصفوفة BSON
type A []interface{}

من خلال الأنواع أعلاه، يمكن بناء استعلامات SQL وكذلك تحويل البيانات.

TIP

يحتوي دليل examples في المشغل على الكثير من أمثلة الاستخدام، حيث عرض المسؤول بشكل مفصل كيفية استخدام الأنواع الأربعة المذكورة أعلاه.

العنوان: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

الاستعلام عن الوثائق

مثال الاستعلام الرسمي: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

أولاً أنشئ قاعدة بيانات user، وأدخل البيانات التالية في المجموعة users

sql
> use user
> db.users.insertMany([
    {
        name: "mike",
        age: 12,

    },
    {
        name: "jenny",
        age: 14,

    },
    {
        name: "jack",
        age: 18,
        address: "usa"
    }
])

الاستعلام عن مستند واحد

go
type User struct {
    Name    string `bson:"name"`
    Age     int    `bson:"age"`
    Address string `bson:"address"`
}

var user User

result := client.Database("user"). // اختيار قاعدة البيانات
                    Collection("users").                     // اختيار المجموعة
                    FindOne(ctx, bson.D{{"address", "usa"}}) // شرط التصفية

// إزالة التسلسل
if err := result.Decode(&user); err != nil {
    log.Panicln(err)
}

fmt.Printf("%+v\n", user)

كود الاستعلام أعلاه يكافئ

sql
db.users.findOne({
    address: "usa"
})

نتيجة الإخراج

{Name:jack Age:18 Address:usa}

الاستعلام عن عدة مستندات

go
type User struct {
   Name    string `bson:"name"`
   Age     int    `bson:"age"`
   Address string `bson:"address"`
}

var users []User

cursor, err := client.Database("user"). // اختيار قاعدة البيانات
               Collection("users"). // اختيار المجموعة
               Find(ctx, bson.D{})  // شرط التصفية

if err != nil {
   log.Panicln(err)
}

if err := cursor.All(ctx, &users); err != nil {
   log.Panicln(err)
}

fmt.Printf("%+v\n", users)

يكافئ

sql
db.users.find({})

المخرجات

[{Name:jack Age:18 Address:usa} {Name:mike Age:12 Address:} {Name:jenny Age:14 Address:}]

عند بناء شروط الاستعلام، يمكن أيضًا استخدام options

go
type User struct {
    Name    string `bson:"name"`
    Age     int    `bson:"age"`
    Address string `bson:"address"`
}

var users []User

find := options.Find()
find.SetSort(bson.M{"age": 1})
find.SetLimit(1)

cursor, err := client.Database("user"). // اختيار قاعدة البيانات
                    Collection("users").      // اختيار المجموعة
                    Find(ctx, bson.D{}, find) // شرط التصفية

if err != nil {
    log.Panicln(err)
}

if err := cursor.All(ctx, &users); err != nil {
    log.Panicln(err)
}

fmt.Printf("%+v\n", users)

يكافئ

db.users.find({}).sort({age:1}).limit(1)

المخرجات

[{Name:mike Age:12 Address:}]

إنشاء المستندات

مثال الإنشاء الرسمي: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

فيما يلي مثال لإنشاء مستند واحد

go
one, err := client.Database("user").Collection("users").InsertOne(ctx, User{
    Name:    "lili",
    Age:     20,
    Address: "china",
})
if err != nil {
    log.Panicln(err)
}
fmt.Println(one.InsertedID)

بعد الإنشاء الناجح سيتم إرجاع ObjectID للمستند

ObjectID("64c60fa01e2548d9e4de6cf4")

فيما يلي مثال لإنشاء عدة مستندات

go
users := []any{User{
    Name:    "john",
    Age:     10,
    Address: "usa",
}, User{
    Name:    "pop",
    Age:     30,
    Address: "uk",
}}

one, err := client.Database("user").Collection("users").InsertMany(ctx, users)
if err != nil {
    log.Panicln(err)
}
fmt.Println(one.InsertedIDs)

بعد الإنشاء الناجح يتم إرجاع مجموعة من ObjectID

[ObjectID("64c610d5aec2618d6ca0b515") ObjectID("64c610d5aec2618d6ca0b516")]

الكودان أعلاه يكافئان db.users.insertOne و db.users.insertMany.

تحديث المستندات

مثال التحديث الرسمي: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

فيما يلي مثال لتحديث مستند واحد، تغيير اسم الشخص المسمى lili إلى mark

go
upres, err := client.Database("user").Collection("users").UpdateOne(ctx, bson.D{
    {"name", "mark"},
},
    bson.D{
       {"$set", bson.D{
          {"name", "lili"},
       }},
    })
if err != nil {
    log.Panicln(err)
}
fmt.Printf("%+v", upres)

يكافئ

sql
db.users.updateOne({
    name: "lili"
}, {
    $set: {
        name: "mark"
    },
})

المخرجات

&{MatchedCount:1 ModifiedCount:1 UpsertedCount:0 UpsertedID:<nil>}

فيما يلي مثال لتحديث عدة مستندات، تحديث عنوان الأشخاص الذين أعمارهم 10 إلى cn

go
upres, err := client.Database("user").Collection("users").UpdateMany(ctx, bson.D{
    {"age", 10},
},
    bson.D{
        {"$set", bson.D{
            {"address", "cn"},
        }},
    })
if err != nil {
    log.Panicln(err)
}
fmt.Printf("%+v", upres)

بالإضافة إلى استخدام Update، يوفر mongo أيضًا Replace، والفرق بينهما أن الأول يقوم بتحديث حقول المستند، بينما الثاني يستبدل المستند بالكامل. مثلاً في الكود التالي، لا حاجة لاستخدام عوامل التشغيل.

go
upres, err := client.Database("user").Collection("users").ReplaceOne(ctx, bson.D{
    {"age", 10},
},
    bson.D{
       {"address", "cn"},
    })
if err != nil {
    log.Panicln(err)
}
fmt.Printf("%+v", upres)

كما يوفر mongo أيضًا FindOneAndUpdate و FindOneAndReplace للحصول على المستند وتحديثه. كالتالي

go
res := client.Database("user").Collection("users").FindOneAndReplace(ctx, bson.D{
    {"address", "cn"},
},
    bson.D{
       {"address", "uk"},
    })
if err := res.Err(); err != nil {
    log.Panicln(err)
}

var user User

res.Decode(&user)

fmt.Printf("%+v", user)

المخرجات

Name: Age:0 Address:cn}

هذه العملية تقوم أولاً بالاستعلام عن المستند ثم تعديله.

حذف المستندات

مثال الحذف الرسمي: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

فيما يلي مثال لحذف مستند واحد

go
result, err := client.Database("user").Collection("users").DeleteOne(ctx, bson.D{
    {"name", "jack"},
})
if err != nil {
    log.Panicln(err)
}
fmt.Println(result.DeletedCount)

فيما يلي مثال لحذف عدة مستندات

go
result, err := client.Database("user").Collection("users").DeleteMany(ctx, bson.D{
    {"age", "10"},
})
if err != nil {
    log.Panicln(err)
}
fmt.Println(result.DeletedCount)

التجميع

مثال التجميع الرسمي: mongo-go-driver/examples/documentation_examples/examples.go at master · mongodb/mongo-go-driver (github.com)

تستخدم عملية التجميع نوع mongo.Pipeline، وهو في الأساس []bson.D

go
type Pipeline []bson.D
go
pipline := mongo.Pipeline{
    {
       {"$match", bson.D{
          {"address", "uk"},
       }},
    },
    {
       {"$sort", bson.D{
          {"age", 1},
       }},
    },
}
aggregate, err := client.Database("user").Collection("users").Aggregate(ctx, pipline)
if err != nil {
    log.Panicln(err)
}
var users []User
if err := aggregate.All(ctx, &users); err != nil {
    log.Panicln(err)
}
log.Println(users)

المخرجات

[{lili 20 uk} {kak 30 uk}]

هذه العملية التجميعية تقوم بمطابقة جميع المستخدمين الذين عنوانهم uk، ثم ترتيبهم حسب العمر.

Golang تم تحريره بواسطة www.golangdev.cn