解组 bson.D 对象(Golang)

huangapple go评论81阅读模式
英文:

Unmarshalling a bson.D object (Golang)

问题

我会尽量清楚地解释。我正在构建一个简单的审计日志API,使用MongoDB和Model-View-Controller架构。作为功能的一部分,用户可以使用HTTP端点请求数据。当命中端点时,控制器包调用模型包,并执行以下代码:

// GetResourceData函数接受资源和提供该资源的日志数据,按日期和时间排序。它还接受context.Context和*mongo.Client作为参数。

func GetResourceData(ctx context.Context, CL *mongo.Client, Resource string) error {
    ourDatabase := CL.Database("Event_Database")
    eventsCollection := ourDatabase.Collection("Events")

    opts := options.Find()
    opts.SetSort(bson.D{{"Date", -1}, {"Time", -1}})

    filterCursor, err := eventsCollection.Find(
        ctx,
        bson.M{"Resource": Resource},
        opts)

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

    defer filterCursor.Close(ctx)
    for filterCursor.Next(ctx) {
        var eventsFiltered []bson.D
        if err = filterCursor.All(ctx, &eventsFiltered); err != nil {
            log.Fatal(err)
        }

        fmt.Println(eventsFiltered)
    }

    return err
}

这个代码运行得很好,正如你所看到的,我已经将eventsFiltered打印到终端上。然而,在那里它没有太多用处,我需要将它打印到屏幕上。我在视图包中有一个准备好的函数,它使用http.ResponseWriter来完成这个任务,但是-我无法弄清楚如何将bson.D转换为字符串格式,以便我可以清晰地将其作为参数传递。如果我尝试使用bson.Unmarshal:

var cookie []byte
bson.Unmarshal(cookie, eventsFiltered)
s := string(cookie)
fmt.Println("Events filtered as a string is: ", s)
fmt.Println("Events filtered as a byte slice is: ", cookie)

我得到以下结果:

Events filtered as a string is: 
Events filtered as a byte slice is:  []

一个空字符串或一个空的字节切片。我知道我漏掉了一些非常简单的东西,但我看不到它!

如果你有任何问题,请随时提问。

谢谢,
A

英文:

I'll try to be as clear as possible. I'm building a simple audit logging API, using MongoDB, and Model-Vew-Controller architecture. As part of the functionality, the user can request data using a http endpoint. When the endpoint is hit, the controller package calls the model package, and the code below is executed:

// The GetResourceData function takes the resource, and provides the log data for that resource, sorted by // date and time. It also takes a context.context, and a *mongo.Client as parameters.

func GetResourceData(ctx context.Context, CL *mongo.Client, Resource string) error { ourDatabase := CL.Database("Event_Database") eventsCollection := ourDatabase.Collection("Events")

opts := options.Find()
opts.SetSort(bson.D{{"Date", -1}, {"Time", -1}})

filterCursor, err := eventsCollection.Find(
	ctx,
	bson.M{"Resource": Resource},
	opts)

if err != nil {

	log.Fatal(err)
}

defer filterCursor.Close(ctx)
for filterCursor.Next(ctx) {

	var eventsFiltered []bson.D
	if err = filterCursor.All(ctx, &eventsFiltered); err != nil {
		log.Fatal(err)
	}

	fmt.Println(eventsFiltered)

}

return err
}

This works fine, and as you can see, I've printed the eventsFiltered to the terminal. It doesn't do much good there however, and I need to print it to the screen. I have a function that's ready to do this in the view package with a http.ResponseWriter, BUT - I cannot figure out how to convert the bson.D to a string format so I can cleanly pass this in as a parameter. If I try bson.Unmarshall;

            var cookie []byte
	bson.Unmarshal(cookie, eventsFiltered)
	s := string(cookie)
	fmt.Println("Events filtered as a string is: ", s)
	fmt.Println("Events filtered as a byte slice is: ", cookie)

I get the following;

Users filtered as a string is:

Users filtered as a byte slice is: []

...an empty string, or an empty byte slice. I know there is something really simple I'm missing, but I can't see it!

Any help would be greatly appreciated. Please ask if you have any questions.

Thanks,
A

答案1

得分: 2

首先,如果你使用filterCursor.All(ctx, &eventsFiltered),你不需要遍历整个集合或关闭游标(游标方法All(...)会为你完成)。

关于你的问题,你可以像这样做:

var eventsFiltered []bson.D
if err = filterCursor.All(ctx, &eventsFiltered); err != nil {
    log.Fatal(err)
}
for _, event := range eventsFiltered {
    for _, keyValPair := range event {
        fmt.Printf("key is %s; val is %v", keyValPair.Key, keyValPair.Value)
    }
}

或者,如果元素的顺序不重要,可以考虑解组成bson.M

var eventsFiltered []bson.M
if err = filterCursor.All(ctx, &eventsFiltered); err != nil {
    log.Fatal(err)
}
for _, event := range eventsFiltered {
    for key, val := range event {
        fmt.Printf("key is %s; val is %v", key, val)
    }
}

因此,整个解决方案如下:

func GetResourceData(ctx context.Context, CL *mongo.Client, Resource string) error {
    ourDatabase := CL.Database("Event_Database")
    eventsCollection := ourDatabase.Collection("Events")

    opts := options.Find()
    opts.SetSort(bson.D{{"Date", -1}, {"Time", -1}})

    filterCursor, err := eventsCollection.Find(
        ctx,
        bson.M{"Resource": Resource},
        opts)

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

    if filterCursor.Next(ctx) {
        var eventsFiltered []bson.M
        if err = filterCursor.All(ctx, &eventsFiltered); err != nil {
            log.Fatal(err)
        }
        // If you need ordered print, uncomment the following lines and comment out following uncommented for loop
        //        for _, event := range eventsFiltered {
        //            for _, keyValPair := range event{
        //                fmt.Printf("key is %s; val is %v", keyValPair.Key, keyValPair.Value)
        //            }
        //        }
        for _, event := range eventsFiltered {
            for key, val := range event {
                fmt.Printf("key is %s; val is %v", key, val)
            }
        }

    }
    return nil
}
英文:

First of all, if you use filterCursor.All(ctx, &eventsFiltered), you don't need to either iterate trough all the collection or close the cursor (cursor method All(...) will do it for you).


What about your question, you can do for example something like this:

		var eventsFiltered []bson.D
		if err = filterCursor.All(ctx, &eventsFiltered); err != nil {
			log.Fatal(err)
		}
		for _, event := range eventsFiltered {
			for _, keyValPair := range event {
				fmt.Printf("key is %s; val is %v", keyValPair.Key, keyValPair.Value)
			}
		}

Or, in case an order of elements doesn't matter, consider unmarshalling into bson.M:

		var eventsFiltered []bson.M
		if err = filterCursor.All(ctx, &eventsFiltered); err != nil {
			log.Fatal(err)
		}
		for _, event := range eventsFiltered {
			for key, val := range event {
				fmt.Printf("key is %s; val is %v", key, val)
			}
		}

So, the whole solution would be:

func GetResourceData(ctx context.Context, CL *mongo.Client, Resource string) error {
	ourDatabase := CL.Database("Event_Database")
	eventsCollection := ourDatabase.Collection("Events")

	opts := options.Find()
	opts.SetSort(bson.D{{"Date", -1}, {"Time", -1}})

	filterCursor, err := eventsCollection.Find(
		ctx,
		bson.M{"Resource": Resource},
		opts)

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

	if filterCursor.Next(ctx) {
		var eventsFiltered []bson.M
		if err = filterCursor.All(ctx, &eventsFiltered); err != nil {
			log.Fatal(err)
		}
		// If you need ordered print, uncomment the following lines and comment out following uncommented for loop
		//        for _, event := range eventsFiltered {
		//            for _, keyValPair := range event{
		//                fmt.Printf("key is %s; val is %v", keyValPair.Key, keyValPair.Value)
		//            }
		//        }
		for _, event := range eventsFiltered {
			for key, val := range event {
				fmt.Printf("key is %s; val is %v", key, val)
			}
		}

	}
	return nil
}

huangapple
  • 本文由 发表于 2022年4月4日 23:37:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/71739971.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定