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 BY
与ORDER BY
结合使用不受支持
Azure Cosmos DB尚不支持GROUP BY
与ORDER BY
结合使用。您将收到以下错误消息:
‘ORDER BY’ is not supported in presence of GROUP BY.
跨分区分页
可以使用OFFSET...LIMIT
子句进行跨分区分页。但是,没有ORDER BY
的查询是不稳定的。返回的结果可能在查询之间不一致。
可能消耗大量内存的查询
以下查询如果针对大型表执行,可能会消耗大量内存:
OFFSET...LIMIT
子句带有大的偏移量或限制值。SELECT DISTINCT
和SELECT 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
更多关于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
}
选择建议
-
REST API 直接调用:
- 适合需要精细控制请求/响应的场景
- 当官方或第三方库不满足需求时
- 学习 Cosmos DB 底层工作原理
-
gocosmos 驱动:
- 提供更高级的抽象,简化开发
- 内置连接池、重试机制等
- 支持批量操作、存储过程等高级功能
在实际项目中,通常推荐使用 gocosmos 驱动,除非有特殊需求必须直接使用 REST API。