Rychlý start: Sestavení aplikace Go pomocí účtu rozhraní SQL API služby Azure Cosmos DB

PLATÍ PRO: ROZHRANÍ SQL API

V tomto rychlém startu vytvoříte ukázkovou aplikaci Go, která ke správě účtu rozhraní SQL API služby Cosmos DB používá sadu Azure SDK for Go.

Azure Cosmos DB je vícemodelová databázová služba, která umožňuje rychle vytvářet a dotazovat dokumenty, tabulky, klíč-hodnota a grafové databáze s možnostmi globální distribuce a horizontálního škálování.

Další informace o službě Azure Cosmos DB najdete v tématu Azure Cosmos DB.

Požadavky

Začínáme

Pro účely tohoto rychlého startu budete muset vytvořit skupinu prostředků Azure a účet Cosmos DB.

Spuštěním následujících příkazů vytvořte skupinu prostředků Azure:

az group create --name myResourceGroup --location eastus

Pak vytvořte účet Cosmos DB spuštěním následujícího příkazu:

az cosmosdb create --name my-cosmosdb-account --resource-group myResourceGroup

Instalace balíčku

go get Pomocí příkazu nainstalujte balíček azcosmos.

go get github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos

Klíčové koncepty

  • A Client je připojení k účtu služby Azure Cosmos DB.
  • Účty Služby Azure Cosmos DB můžou mít více databases. A DatabaseClient umožňuje vytvářet, číst a odstraňovat databáze.
  • Databáze v rámci účtu služby Azure Cosmos může mít více containers. A ContainerClient umožňuje vytvářet, číst, aktualizovat a odstraňovat kontejnery a upravovat zřizování propustnosti.
  • Informace se ukládají jako položky uvnitř kontejnerů. A klient umožňuje vytvářet, číst, aktualizovat a odstraňovat položky v kontejnerech.

Příklady kódu

Ověření klienta

var endpoint = "<azure_cosmos_uri>"
var key      = "<azure_cosmos_primary_key"

cred, err := azcosmos.NewKeyCredential(key)
if err != nil {
    log.Fatal("Failed to create a credential: ", err)
}

// Create a CosmosDB client
client, err := azcosmos.NewClientWithKey(endpoint, cred, nil)
if err != nil {
    log.Fatal("Failed to create cosmos client: ", err)
}

// Create database client
databaseClient, err := client.NewDatabase("<databaseName>")
if err != nil {
    log.Fatal("Failed to create database client:", err)
}

// Create container client
containerClient, err := client.NewContainer("<databaseName>", "<containerName>")
if err != nil {
    log.Fatal("Failed to create a container client:", err)
}

Vytvoření databáze Cosmos DB

import (
	"context"
	"log"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func createDatabase (client *azcosmos.Client, databaseName string) error {
//	databaseName := "adventureworks"

	// sets the name of the database
	databaseProperties := azcosmos.DatabaseProperties{ID: databaseName}

	// creating the database
	ctx := context.TODO()
	databaseResp, err := client.CreateDatabase(ctx, databaseProperties, nil)
	if err != nil {
		log.Fatal(err)
	}
	return nil
}

Vytvoření kontejneru

import (
	"context"
	"log"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func createContainer (client *azcosmos.Client, databaseName, containerName, partitionKey string) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "/customerId"
	
	databaseClient, err := client.NewDatabase(databaseName) // returns a struct that represents a database
	if err != nil {
		log.Fatal("Failed to create a database client:", err)
	}

	// Setting container properties
	containerProperties := azcosmos.ContainerProperties{
		ID: containerName,
		PartitionKeyDefinition: azcosmos.PartitionKeyDefinition{
			Paths: []string{partitionKey},
		},
	}

	// Setting container options 
	throughputProperties := azcosmos.NewManualThroughputProperties(400) //defaults to 400 if not set
	options := &azcosmos.CreateContainerOptions{
		ThroughputProperties: &throughputProperties,
	}

	ctx := context.TODO()
	containerResponse, err := databaseClient.CreateContainer(ctx, containerProperties, options)
	if err != nil {
		log.Fatal(err)

	}
	log.Printf("Container [%v] created. ActivityId %s\n", containerName, containerResponse.ActivityID)
	
	return nil
}

Vytvoření položky

import (
	"context"
	"log"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func createItem(client *azcosmos.Client, databaseName, containerName, partitionKey string, item any) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"
/*
	item = struct {
		ID           string `json:"id"`
		CustomerId   string `json:"customerId"`
		Title        string
		FirstName    string
		LastName     string
		EmailAddress string
		PhoneNumber  string
		CreationDate string
	}{
		ID:           "1",
		CustomerId:   "1",
		Title:        "Mr",
		FirstName:    "Luke",
		LastName:     "Hayes",
		EmailAddress: "luke12@adventure-works.com",
		PhoneNumber:  "879-555-0197",
	}
*/
	// Create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("failed to create a container client: %s", err)
	}

	// Specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	b, err := json.Marshal(item)
	if err != nil {
		return err
	}
	// setting item options upon creating ie. consistency level
	itemOptions := azcosmos.ItemOptions{
		ConsistencyLevel: azcosmos.ConsistencyLevelSession.ToPtr(),
	}
	ctx := context.TODO()
	itemResponse, err := containerClient.CreateItem(ctx, pk, b, &itemOptions)

	if err != nil {
		return err
	}
	log.Printf("Status %d. Item %v created. ActivityId %s. Consuming %v Request Units.\n", itemResponse.RawResponse.StatusCode, pk, itemResponse.ActivityID, itemResponse.RequestCharge)

	return nil
}

Čtení položky

import (
	"context"
	"log"
	"fmt"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func readItem(client *azcosmos.Client, databaseName, containerName, partitionKey, itemId string) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"
//	itemId = "1"

	// Create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("Failed to create a container client: %s", err)
	}

	// Specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	// Read an item
	ctx := context.TODO()
	itemResponse, err := containerClient.ReadItem(ctx, pk, itemId, nil)
	if err != nil {
		return err
	}

	itemResponseBody := struct {
		ID           string `json:"id"`
		CustomerId   string `json:"customerId"`
		Title        string
		FirstName    string
		LastName     string
		EmailAddress string
		PhoneNumber  string
		CreationDate string
	}{}

	err = json.Unmarshal(itemResponse.Value, &itemResponseBody)
	if err != nil {
		return err
	}

	b, err := json.MarshalIndent(itemResponseBody, "", "    ")
	if err != nil {
		return err
	}
	fmt.Printf("Read item with customerId %s\n", itemResponseBody.CustomerId)
	fmt.Printf("%s\n", b)

	log.Printf("Status %d. Item %v read. ActivityId %s. Consuming %v Request Units.\n", itemResponse.RawResponse.StatusCode, pk, itemResponse.ActivityID, itemResponse.RequestCharge)

	return nil
}

Odstranění položky

import (
	"context"
	"log"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func deleteItem(client *azcosmos.Client, databaseName, containerName, partitionKey, itemId string) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"
//	itemId = "1"

	// Create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("Failed to create a container client: %s", err)
	}
	// Specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	// Delete an item
	ctx := context.TODO()
	res, err := containerClient.DeleteItem(ctx, pk, itemId, nil)
	if err != nil {
		return err
	}

	log.Printf("Status %d. Item %v deleted. ActivityId %s. Consuming %v Request Units.\n", res.RawResponse.StatusCode, pk, res.ActivityID, res.RequestCharge)

	return nil
}

Spuštění kódu

K ověření musíte aplikaci předat přihlašovací údaje k účtu služby Azure Cosmos.

Pomocí následujícího postupu získejte přihlašovací údaje ke svému účtu Azure Cosmos:

  1. Přihlaste se k webu Azure Portal.

  2. Přejděte ke svému účtu Azure Cosmos.

  3. Otevřete podokno Klíče a zkopírujte identifikátor URI a PRIMÁRNÍ KLÍČ vašeho účtu. Hodnoty identifikátoru URI a klíčů přidáte do proměnné prostředí v dalším kroku.

Po zkopírování identifikátoru URI a PRIMÁRNÍho klíče účtu je uložte do nové proměnné prostředí na místním počítači, na kterém běží aplikace.

Hodnoty zkopírované z Azure Portal použijte k nastavení následujících proměnných prostředí:

export AZURE_COSMOS_ENPOINT=<Your_AZURE_COSMOS_URI>
export AZURE_COSMOS_KEY=<Your_COSMOS_PRIMARY_KEY>

Spuštěním následujícího příkazu vytvořte nový modul Go:

go mod init azcosmos

package main

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"os"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func main() {
	endpoint := os.Getenv("AZURE_COSMOS_ENDPOINT")
	if endpoint == "" {
		log.Fatal("AZURE_COSMOS_ENDPOINT could not be found")
	}

	key := os.Getenv("AZURE_COSMOS_KEY")
	if key == "" {
		log.Fatal("AZURE_COSMOS_KEY could not be found")
	}

	var databaseName = "adventureworks"
	var containerName = "customer"
	var partitionKey = "/customerId"

	item := struct {
		ID           string `json:"id"`
		CustomerId   string `json:"customerId"`
		Title        string
		FirstName    string
		LastName     string
		EmailAddress string
		PhoneNumber  string
		CreationDate string
	}{
		ID:           "1",
		CustomerId:   "1",
		Title:        "Mr",
		FirstName:    "Luke",
		LastName:     "Hayes",
		EmailAddress: "luke12@adventure-works.com",
		PhoneNumber:  "879-555-0197",
	}

	cred, err := azcosmos.NewKeyCredential(key)
	if err != nil {
		log.Fatal("Failed to create a credential: ", err)
	}

	// Create a CosmosDB client
	client, err := azcosmos.NewClientWithKey(endpoint, cred, nil)
	if err != nil {
		log.Fatal("Failed to create cosmos db client: ", err)
	}
	
	err = createDatabase(client, databaseName)
	if err != nil {
		log.Printf("createDatabase failed: %s\n", err)
	}

	err = createContainer(client, databaseName, containerName, partitionKey)
	if err != nil {
		log.Printf("createContainer failed: %s\n", err)
	}

	err = createItem(client, databaseName, containerName, item.CustomerId, item)
	if err != nil {
		log.Printf("createItem failed: %s\n", err)
	}

	err = readItem(client, databaseName, containerName, item.CustomerId, item.ID)
	if err != nil {
		log.Printf("readItem failed: %s\n", err)
	}
	
	err = deleteItem(client, databaseName, containerName, item.CustomerId, item.ID)
	if err != nil {
		log.Printf("deleteItem failed: %s\n", err)
	}
}

func createDatabase(client *azcosmos.Client, databaseName string) error {
//	databaseName := "adventureworks"

	databaseProperties := azcosmos.DatabaseProperties{ID: databaseName}

	// This is a helper function that swallows 409 errors
	errorIs409 := func(err error) bool {
		var responseErr *azcore.ResponseError
		return err != nil && errors.As(err, &responseErr) && responseErr.StatusCode == 409
	}
	ctx := context.TODO()
	databaseResp, err := client.CreateDatabase(ctx, databaseProperties, nil)

	switch {
	case errorIs409(err):
		log.Printf("Database [%s] already exists\n", databaseName)
	case err != nil:
		return err
	default:
		log.Printf("Database [%v] created. ActivityId %s\n", databaseName, databaseResp.ActivityID)
	}
	return nil
}

func createContainer(client *azcosmos.Client, databaseName, containerName, partitionKey string) error {
//	databaseName = adventureworks
//	containerName = customer
//	partitionKey = "/customerId"

	databaseClient, err := client.NewDatabase(databaseName)
	if err != nil {
		return err
	}

	// creating a container
	containerProperties := azcosmos.ContainerProperties{
		ID: containerName,
		PartitionKeyDefinition: azcosmos.PartitionKeyDefinition{
			Paths: []string{partitionKey},
		},
	}

	// this is a helper function that swallows 409 errors
	errorIs409 := func(err error) bool {
		var responseErr *azcore.ResponseError
		return err != nil && errors.As(err, &responseErr) && responseErr.StatusCode == 409
	}

	// setting options upon container creation
	throughputProperties := azcosmos.NewManualThroughputProperties(400) //defaults to 400 if not set
	options := &azcosmos.CreateContainerOptions{
		ThroughputProperties: &throughputProperties,
	}
	ctx := context.TODO()
	containerResponse, err := databaseClient.CreateContainer(ctx, containerProperties, options)
	
	switch {
	case errorIs409(err):
		log.Printf("Container [%s] already exists\n", containerName)
	case err != nil:
		return err
	default:
		log.Printf("Container [%s] created. ActivityId %s\n", containerName, containerResponse.ActivityID)
	}
	return nil
}

func createItem(client *azcosmos.Client, databaseName, containerName, partitionKey string, item any) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"

/*	item = struct {
		ID           string `json:"id"`
		CustomerId   string `json:"customerId"`
		Title        string
		FirstName    string
		LastName     string
		EmailAddress string
		PhoneNumber  string
		CreationDate string
	}{
		ID:           "1",
		CustomerId:   "1",
		Title:        "Mr",
		FirstName:    "Luke",
		LastName:     "Hayes",
		EmailAddress: "luke12@adventure-works.com",
		PhoneNumber:  "879-555-0197",
		CreationDate: "2014-02-25T00:00:00",
	}
*/
	// create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("failed to create a container client: %s", err)
	}

	// specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	b, err := json.Marshal(item)
	if err != nil {
		return err
	}
	// setting the item options upon creating ie. consistency level
	itemOptions := azcosmos.ItemOptions{
		ConsistencyLevel: azcosmos.ConsistencyLevelSession.ToPtr(),
	}

	// this is a helper function that swallows 409 errors
	errorIs409 := func(err error) bool {
		var responseErr *azcore.ResponseError
		return err != nil && errors.As(err, &responseErr) && responseErr.StatusCode == 409
	}

	ctx := context.TODO()
	itemResponse, err := containerClient.CreateItem(ctx, pk, b, &itemOptions)
	
	switch {
	case errorIs409(err):
		log.Printf("Item with partitionkey value %s already exists\n", pk)
	case err != nil:
		return err
	default:
		log.Printf("Status %d. Item %v created. ActivityId %s. Consuming %v Request Units.\n", itemResponse.RawResponse.StatusCode, pk, itemResponse.ActivityID, itemResponse.RequestCharge)
	}
	
	return nil
}

func readItem(client *azcosmos.Client, databaseName, containerName, partitionKey, itemId string) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"
//	itemId = "1"

	// Create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("failed to create a container client: %s", err)
	}

	// Specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	// Read an item
	ctx := context.TODO()
	itemResponse, err := containerClient.ReadItem(ctx, pk, itemId, nil)
	if err != nil {
		return err
	}

	itemResponseBody := struct {
		ID           string `json:"id"`
		CustomerId   string `json:"customerId"`
		Title        string
		FirstName    string
		LastName     string
		EmailAddress string
		PhoneNumber  string
		CreationDate string
	}{}

	err = json.Unmarshal(itemResponse.Value, &itemResponseBody)
	if err != nil {
		return err
	}

	b, err := json.MarshalIndent(itemResponseBody, "", "    ")
	if err != nil {
		return err
	}
	fmt.Printf("Read item with customerId %s\n", itemResponseBody.CustomerId)
	fmt.Printf("%s\n", b)

	log.Printf("Status %d. Item %v read. ActivityId %s. Consuming %v Request Units.\n", itemResponse.RawResponse.StatusCode, pk, itemResponse.ActivityID, itemResponse.RequestCharge)

	return nil
}

func deleteItem(client *azcosmos.Client, databaseName, containerName, partitionKey, itemId string) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"
//	itemId = "1"

	// Create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("failed to create a container client:: %s", err)
	}
	// Specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	// Delete an item
	ctx := context.TODO()

	res, err := containerClient.DeleteItem(ctx, pk, itemId, nil)
	if err != nil {
		return err
	}

	log.Printf("Status %d. Item %v deleted. ActivityId %s. Consuming %v Request Units.\n", res.RawResponse.StatusCode, pk, res.ActivityID, res.RequestCharge)

	return nil
}

Vytvořte nový soubor s názvem main.go a zkopírujte kód z výše uvedené ukázkové části.

Spusťte aplikaci spuštěním následujícího příkazu:

go run main.go

Vyčištění prostředků

Až skončíte s aplikací a účtem služby Azure Cosmos DB, můžete prostředky Azure, které jste vytvořili, odstranit, takže vám nebudou účtovány další poplatky. Odstranění prostředků:

  1. Na panelu hledání Azure Portal vyhledejte a vyberte skupiny prostředků.

  2. V seznamu vyberte skupinu prostředků, kterou jste vytvořili pro účely tohoto rychlého startu.

    Vyberte skupinu prostředků, která se má odstranit.

  3. Na stránce Přehled skupiny prostředků vyberte Odstranit skupinu prostředků.

    Odstranění skupiny prostředků

  4. V dalším okně zadejte název skupiny prostředků, která chcete odstranit, a pak vyberte Odstranit.

Další kroky

V tomto rychlém startu jste zjistili, jak vytvořit účet služby Azure Cosmos DB, vytvořit databázi, kontejner a položku položky. Teď naimportujte další data do účtu služby Azure Cosmos DB.

Pokoušíte se naplánovat kapacitu migrace do služby Azure Cosmos DB? Informace o stávajícím databázovém clusteru můžete použít k plánování kapacity.