golang Azure Cosmos DB REST客户端和标准驱动插件库gocosmos的使用

golang Azure Cosmos DB REST客户端和标准驱动插件库gocosmos的使用

gocosmos

Go语言驱动,用于Azure Cosmos DB SQL API,可以与标准的database/sql包一起使用。还包含一个REST客户端。

database/sql驱动

支持的SQL语句摘要:

语句 语法
创建新数据库 CREATE DATABASE [IF NOT EXISTS] <db-name>
更改数据库吞吐量 ALTER DATABASE <db-name> WITH RU/MAXRU=<ru>
删除现有数据库 DROP DATABASE [IF EXISTS] <db-name>
列出所有现有数据库 LIST DATABASES
创建新集合 CREATE COLLECTION [IF NOT EXISTS] [<db-name>.]<collection-name> <WITH PK=partitionKey>
更改集合吞吐量 ALTER COLLECTION [<db-name>.]<collection-name> WITH RU/MAXRU=<ru>
删除现有集合 DROP COLLECTION [IF EXISTS] [<db-name>.]<collection-name>
列出数据库中所有现有集合 LIST COLLECTIONS [FROM <db-name>]
向集合中插入新文档 INSERT INTO [<db-name>.]<collection-name> ...
插入或替换文档 UPSERT INTO [<db-name>.]<collection-name> ...
删除现有文档 DELETE FROM [<db-name>.]<collection-name> WHERE id=<id-value>
更新现有文档 UPDATE [<db-name>.]<collection-name> SET ... WHERE id=<id-value>
查询集合中的文档 SELECT [CROSS PARTITION] ... FROM <collection-name> ... [WITH database=<db-name>]

Azure Cosmos DB SQL API目前仅支持SELECT语句。gocosmos通过将SQL语句转换为REST API调用来实现其他语句。

示例用法:

package main

import (
	"database/sql"
	_ "github.com/btnguyen2k/gocosmos"
)

func main() {
	driver := "gocosmos"
	dsn := "AccountEndpoint=https://localhost:8081/;AccountKey=<cosmosdb-account-key>"
	db, err := sql.Open(driver, dsn)
	if err != nil {
		panic(err)
	}
	defer db.Close()
	
	_, err = db.Exec("CREATE DATABASE mydb WITH maxru=10000")
	if err != nil {
		panic(err)
	}
	
	// 数据库"mydb"已成功创建
}

Cosmos DB的数据源名称(DSN)语法

注意:换行仅为了可读性!

AccountEndpoint=<cosmosdb-endpoint>
;AccountKey=<cosmosdb-account-key>
[;TimeoutMs=<timeout-in-ms>]
[;Version=<cosmosdb-api-version>]
[;DefaultDb|Db=<db-name>]
[;AutoId=<true/false>]
[;InsecureSkipVerify=<true/false>]
  • AccountEndpoint: (必需) 访问Cosmos DB的端点。例如,本地运行的Azure Cosmos DB模拟器的端点是https://localhost:8081/
  • AccountKey: (必需) 用于身份验证的账户密钥。
  • TimeoutMs: (可选) 操作超时时间(毫秒)。如果未指定,默认值为10秒
  • Version: (可选) 要使用的Cosmos DB版本。如果未指定,默认值为2020-07-15
  • DefaultDb: (可选) 指定Cosmos DB操作中使用的默认数据库。也可以使用别名Db代替DefaultDb
  • AutoId: (可选) 参见自动ID部分。
  • InsecureSkipVerify: (可选) 如果为true,则禁用https端点的CA验证(对于使用本地/docker Cosmos DB模拟器的测试/开发环境很有用)。

自动ID

Azure Cosmos DB要求每个文档都有一个唯一ID字段来标识文档。在创建新文档时,如果没有提供唯一ID字段的值,gocosmos能够自动生成一个。通过在数据源名称(对于database/sql驱动)或连接字符串(对于REST客户端)中指定设置AutoId=true来启用此功能。如果未指定,默认值为AutoId=true

已知问题

GROUP BYORDER BY结合使用不受支持

Azure Cosmos DB尚不支持GROUP BYORDER BY结合使用。您将收到以下错误消息:

‘ORDER BY’ is not supported in presence of GROUP BY.

跨分区分页

可以使用OFFSET...LIMIT子句进行跨分区分页。但是,没有ORDER BY的查询是不稳定的。返回的结果可能在查询之间不一致。

可能消耗大量内存的查询

以下查询如果针对大型表执行,可能会消耗大量内存:

  • OFFSET...LIMIT子句带有大的偏移量或限制值。
  • SELECT DISTINCTSELECT DISTINCT VALUE查询。
  • 带有GROUP BY子句的查询。

REST客户端

许可证

该项目采用MIT许可证 - 有关详细信息,请参阅LICENSE.md文件。

支持和贡献

免责声明:我也是microsoft/gocosmos的核心维护者。功能和错误修复在两个项目之间同步。

该项目使用GitHub Issues来跟踪错误和功能请求。在提交新问题之前,请搜索现有问题以避免重复。对于新问题,请将您的错误或功能请求作为新问题提交。

请在microsoft/gocosmos存储库中创建拉取请求。

如果您发现这个项目有用,请给它点赞。


更多关于golang Azure Cosmos DB REST客户端和标准驱动插件库gocosmos的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang Azure Cosmos DB REST客户端和标准驱动插件库gocosmos的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 与 Azure Cosmos DB:REST 客户端和 gocosmos 驱动使用指南

Azure Cosmos DB 是微软提供的全球分布式多模型数据库服务。在 Golang 中,我们可以通过两种主要方式与 Cosmos DB 交互:使用 REST API 直接调用,或者使用 gocosmos 驱动库。

1. 使用 REST API 客户端

直接使用 REST API 可以让你更底层地控制与 Cosmos DB 的交互。以下是基本示例:

package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

const (
	cosmosEndpoint = "https://<your-account>.documents.azure.com:443/"
	cosmosKey      = "<your-primary-key>"
	databaseName   = "testdb"
	collectionName = "testcollection"
)

func generateAuthHeader(method, resourceType, resourceLink, date string) string {
	// 实际实现中需要生成正确的授权头
	// 这里简化示例
	return "type=master&ver=1.0&sig=<signature>"
}

func cosmosRequest(ctx context.Context, method, path string, body interface{}) ([]byte, error) {
	url := cosmosEndpoint + path
	date := time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05 GMT")
	
	var reqBody []byte
	if body != nil {
		var err error
		reqBody, err = json.Marshal(body)
		if err != nil {
			return nil, err
		}
	}
	
	req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewBuffer(reqBody))
	if err != nil {
		return nil, err
	}
	
	req.Header.Set("x-ms-date", date)
	req.Header.Set("x-ms-version", "2018-12-31")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", generateAuthHeader(method, "docs", "dbs/"+databaseName+"/colls/"+collectionName, date))
	
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	
	return ioutil.ReadAll(resp.Body)
}

func main() {
	ctx := context.Background()
	
	// 创建文档示例
	doc := map[string]interface{}{
		"id":      "1",
		"name":    "John Doe",
		"email":   "john@example.com",
		"country": "USA",
	}
	
	response, err := cosmosRequest(ctx, "POST", 
		fmt.Sprintf("dbs/%s/colls/%s/docs", databaseName, collectionName), doc)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	
	fmt.Printf("Response: %s\n", response)
}

2. 使用 gocosmos 驱动库

gocosmos 是一个非官方的 Go 语言 Cosmos DB SDK,提供了更高级的抽象。

首先安装驱动:

go get github.com/btnguyen2k/gocosmos

基本使用示例

package main

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

	"github.com/btnguyen2k/gocosmos"
)

func main() {
	// 1. 创建客户端
	client := gocosmos.NewRestClient(nil, "<your-account>", "<your-primary-key>", "<your-database>")
	
	// 2. 检查连接
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	
	if _, err := client.GetDatabase(ctx, "<your-database>"); err != nil {
		log.Fatalf("Failed to connect to Cosmos DB: %v", err)
	}
	
	// 3. 创建集合(如果不存在)
	collectionSpec := gocosmos.CollectionSpec{
		DbName:           "<your-database>",
		CollectionName:   "users",
		PartitionKeyInfo: map[string]interface{}{"paths": []string{"/country"}, "kind": "Hash"},
	}
	if _, err := client.CreateCollection(ctx, collectionSpec); err != nil {
		log.Printf("Warning: collection may already exist: %v", err)
	}
	
	// 4. 插入文档
	doc := map[string]interface{}{
		"id":      "user1",
		"name":    "Alice",
		"email":   "alice@example.com",
		"country": "Canada",
	}
	
	if result, err := client.CreateDocument(ctx, "<your-database>", "users", doc); err != nil {
		log.Fatalf("Failed to create document: %v", err)
	} else {
		fmt.Printf("Created document with ID: %s\n", result.Document["id"])
	}
	
	// 5. 查询文档
	query := "SELECT * FROM users u WHERE u.country = @country"
	params := map[string]interface{}{"@country": "Canada"}
	
	if result, err := client.QueryDocuments(ctx, "<your-database>", "users", query, params); err != nil {
		log.Fatalf("Failed to query documents: %v", err)
	} else {
		fmt.Println("Query results:")
		for _, doc := range result.Documents {
			fmt.Printf("- %v\n", doc)
		}
	}
}

高级功能

批量操作

// 批量插入文档
func batchInsert(client *gocosmos.RestClient, dbName, collName string, docs []map[string]interface{}) error {
	ctx := context.Background()
	
	// 开始批量操作
	batch := client.NewBatchOperation(dbName, collName)
	
	// 添加文档到批量操作
	for _, doc := range docs {
		batch.AddDocument(doc, nil)
	}
	
	// 执行批量操作
	result, err := client.ExecuteBatch(ctx, batch)
	if err != nil {
		return err
	}
	
	fmt.Printf("Batch operation completed. Success: %d, Failed: %d\n", 
		result.NumberOfSuccessfulOperations(), result.NumberOfFailedOperations())
	
	return nil
}

存储过程

// 创建和执行存储过程
func createAndExecuteStoredProc(client *gocosmos.RestClient) error {
	ctx := context.Background()
	dbName := "testdb"
	collName := "users"
	
	// 存储过程代码
	sprocBody := `function(country) {
		var context = getContext();
		var collection = context.getCollection();
		var response = context.getResponse();
		
		var query = "SELECT * FROM users u WHERE u.country = '" + country + "'";
		var accepted = collection.queryDocuments(
			collection.getSelfLink(),
			query,
			{},
			function(err, docs, options) {
				if (err) throw err;
				response.setBody(docs);
			}
		);
		if (!accepted) throw new Error("Query not accepted");
	}`
	
	// 创建存储过程
	sproc := gocosmos.StoredProcedureSpec{
		DbName:         dbName,
		CollName:       collName,
		SprocName:      "getUsersByCountry",
		SprocBody:      sprocBody,
	}
	
	if _, err := client.CreateStoredProcedure(ctx, sproc); err != nil {
		return fmt.Errorf("failed to create stored procedure: %v", err)
	}
	
	// 执行存储过程
	params := []interface{}{"Canada"}
	result, err := client.ExecuteStoredProcedure(ctx, dbName, collName, "getUsersByCountry", params)
	if err != nil {
		return fmt.Errorf("failed to execute stored procedure: %v", err)
	}
	
	fmt.Printf("Stored procedure result: %v\n", result)
	return nil
}

选择建议

  1. REST API 直接调用

    • 适合需要精细控制请求/响应的场景
    • 当官方或第三方库不满足需求时
    • 学习 Cosmos DB 底层工作原理
  2. gocosmos 驱动

    • 提供更高级的抽象,简化开发
    • 内置连接池、重试机制等
    • 支持批量操作、存储过程等高级功能

在实际项目中,通常推荐使用 gocosmos 驱动,除非有特殊需求必须直接使用 REST API。

回到顶部