Pretty print Golang pipelines

I might be overlooking something obvious, but is there a way to pretty print a pipeline built in Go using mongo.Pipeline{}, bson.M{} etc?

Something a bit more readable in a log that this!

2023-02-13T16:15:29.389-05:00	(mongo.Pipeline) (len=10 cap=14) {
2023-02-13T16:15:29.389-05:00	(primitive.D) (len=1 cap=1) {
2023-02-13T16:15:29.389-05:00	(primitive.E) {
2023-02-13T16:15:29.389-05:00	Key: (string) (len=6) "$match",
2023-02-13T16:15:29.389-05:00	Value: (primitive.M) (len=1) {
2023-02-13T16:15:29.389-05:00	(string) (len=17) "summary": (primitive.M) (len=1) {
2023-02-13T16:15:29.389-05:00	(string) (len=7) "$exists": (bool) true
2023-02-13T16:15:29.389-05:00	}
2023-02-13T16:15:29.389-05:00	}
2023-02-13T16:15:29.389-05:00	}
2023-02-13T16:15:29.389-05:00	},

Hi :wave: @Ben_Giddins,

Welcome to the MongoDB Community forums :sparkles:

Here, you can use bson.Marshal() to convert each pipeline element to a BSON document. After that, you can use bson.Unmarshal() to convert the BSON document to a bson.M value for pretty printing.

Finally, you can use json.MarshalIndent to format the output. Here, each JSON element in the output will begin on a new line beginning with a prefix followed by one or more copies of indent according to the indentation nesting you have provided.

Here is the code snippet for your reference:

package main

import (
	"encoding/json"
	"fmt"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
)

func main() {
	pipeline := mongo.Pipeline{
		bson.D{{"$match", bson.M{"age": bson.M{"$gt": 100}}}},
		bson.D{{"$group", bson.M{"count": bson.M{"$sum": 1}}}},
		bson.D{{"$sort", bson.M{"count": -1}}},
		bson.D{{"$limit", 10}},
	}
	var prettyDocs []bson.M
	for _, doc := range pipeline {
		bsonDoc, err := bson.Marshal(doc)
		if err != nil {
			panic(err)
		}
		var prettyDoc bson.M
		err = bson.Unmarshal(bsonDoc, &prettyDoc)
		if err != nil {
			panic(err)
		}
		prettyDocs = append(prettyDocs, prettyDoc)
	}
	prettyJSON, err := json.MarshalIndent(prettyDocs, "", "  ")
	if err != nil {
		panic(err)
	}

	fmt.Println(string(prettyJSON))
}

It will return the output as follow:

[
  {
    "$match": {
      "age": {
        "$gt": 100
      }
    }
  },
  {
    "$group": {
      "count": {
        "$sum": 1
      }
    }
  },
  {
    "$sort": {
      "count": -1
    }
  },
  {
    "$limit": 10
  }
]

I hope it helps!

Best,
Kushagra

Thank you! This is perfect.

Minor tweak - in AWS Lambda, newline characters need to be replaced by a carriage return to get a single block of output in CloudWatch:

	result := bytes.Replace(prettyJSON, []byte("\n"), []byte("\r"), -1)
	fmt.Println(string(result))