Golang中MongoDB(Mgo)管道操作解析

Golang中MongoDB(Mgo)管道操作解析 大家好

想了解如何访问Mongo集合管道聚合的结果。根据我在网上看到的所有示例或博客,结果是[]bson.M{}类型。在记录日志时,我看到结果是一个映射数组/切片,其中还包含嵌套的映射。该如何提取它?我没有看到任何关于访问结果的示例,比如将结果值映射回某个结构体。

提前感谢。

4 回复

问题在于如何访问 bson.m{} 数组的字段,在这种情况下它应该是一个映射。

更多关于Golang中MongoDB(Mgo)管道操作解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


@sandyethadka

能否请你发布有疑问的代码片段?这样我们更容易理解具体问题。

这是关于映射的很好入门资料:https://blog.golang.org/go-maps-in-action

测试查询

type message struct {
	ID int64 `bson:"_id"`
	Size     int64 `bson:"size"`
}

func (e *ets) get(ctx context.Context, clientID int64) (int64, error) {
	sess := e.mgoSess.Copy()
	defer sess.Close()
	var result []*message
	pipeline := []bson.M{
		{
			"$match": bson.M{
				"id":   ID,
			},
		},
		{
			"$group": bson.M{
				"_id":       "null",
				"size": bson.M{"$sum": "$size"},
			},
		},
		{
			"$project": bson.M{
				"size": 1,
			},
		},
	}
	err := sess.
		DB("").
		C(collection).
		Pipe(pipeline).All(ctx, &result)
	if err != nil {
		err = errors.New("MongoDB find aggregation")
		return 0, err
	}
	if len(result) == 0 {
		return 0, nil
	}
	return result[0].Size, nil
}

在Go语言中使用mgo库进行MongoDB管道聚合时,聚合结果通常以[]bson.M类型返回。要访问这些结果,可以通过遍历切片并解析每个bson.M映射中的字段。如果需要将结果映射到结构体,可以使用bson.UnmarshalmgoIter.All方法结合自定义结构体。

以下是一个完整示例,展示如何执行管道聚合并提取结果:

package main

import (
    "fmt"
    "log"

    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

// 定义结构体以映射聚合结果
type AggregationResult struct {
    ID    string `bson:"_id"`
    Count int    `bson:"count"`
    Total int    `bson:"total"`
}

func main() {
    // 连接到MongoDB
    session, err := mgo.Dial("localhost")
    if err != nil {
        log.Fatal(err)
    }
    defer session.Close()

    collection := session.DB("testdb").C("testcollection")

    // 定义管道阶段
    pipeline := []bson.M{
        {
            "$group": bson.M{
                "_id":   "$category",
                "count": bson.M{"$sum": 1},
                "total": bson.M{"$sum": "$value"},
            },
        },
    }

    // 执行聚合操作
    var results []bson.M
    err = collection.Pipe(pipeline).All(&results)
    if err != nil {
        log.Fatal(err)
    }

    // 方法1:直接访问bson.M结果
    fmt.Println("Raw bson.M results:")
    for _, result := range results {
        id := result["_id"]
        count := result["count"]
        total := result["total"]
        fmt.Printf("ID: %v, Count: %v, Total: %v\n", id, count, total)
    }

    // 方法2:将结果映射到结构体切片
    var structuredResults []AggregationResult
    for _, result := range results {
        // 将bson.M转换为bson字节
        data, err := bson.Marshal(result)
        if err != nil {
            log.Fatal(err)
        }

        var structured AggregationResult
        err = bson.Unmarshal(data, &structured)
        if err != nil {
            log.Fatal(err)
        }
        structuredResults = append(structuredResults, structured)
    }

    fmt.Println("\nStructured results:")
    for _, result := range structuredResults {
        fmt.Printf("ID: %s, Count: %d, Total: %d\n", result.ID, result.Count, result.Total)
    }
}

在这个示例中:

  1. 首先执行管道聚合,结果存储在[]bson.M中。
  2. 直接访问bson.M中的字段,使用键名如result["_id"]
  3. 通过bson.Marshalbson.Unmarshal将每个bson.M映射到自定义结构体AggregationResult

如果聚合结果字段固定,也可以直接使用结构体切片接收结果:

var structuredResults []AggregationResult
err = collection.Pipe(pipeline).All(&structuredResults)
if err != nil {
    log.Fatal(err)
}

这种方式要求结构体字段的bson标签与聚合输出字段完全匹配。

回到顶部