How to return aggregated document from MongoDB in Golang?

Viewed 34

I am trying to aggregate field category (which is actually an ObjectId, but I found it more convinient to work if it is string) in my pretty generic blog post model:

type Post struct {
    ID          primitive.ObjectID       `json:"_id" bson:"_id,omitempty"`
    Title       *string                  `json:"title" bson:"title"`
    Slug        *string                  `json:"slug" bson:"slug"`
    Content     []map[string]interface{} `json:"content" bson:"content,omitempty"`
    Category    *string                  `json:"category" bson:"category,omitempty"`
}

I have this pipeline:

match := bson.D{
    {
        "$match", bson.D{
            {
                "slug", slug,
            },
        },
    },
}

lookup := bson.D{
    {
        "$lookup", bson.D{
            {
                "from", categories.Model_name,
            },
            {
                "localField", "category",
            },
            {
                "foreignField", "_id",
            },
            {
                "as", "category",
            },
        },
    },
}

unwind := bson.D{
    {
        "$unwind", bson.D{
            {
                "path", "$category",
            },
        },
    },
}

cursor, err := collection.Aggregate(context.TODO(), mongo.Pipeline{match, lookup, unwind})

var results []Post
if err = cursor.All(context.TODO(), &results); err != nil {
    panic(err)
}

But I am getting this error: panic: error decoding key category: cannot decode array into a string type.

And yeah, it's kinda clear that in my struct category field is just a string and I am trying to put there other type, but what I have to do? I think that creating another struct for this case would be at least inefficient. Let's say if in another function I will want to aggregate another field? Another struct will be needed?

Also, I'm not sure if I'm doing the pipeline thing right, because with that unwind stage the results are empty. If I exclude that stage, I got my results but couldn't decode them.

And I have to mention that the goal is just to get single document from collection and aggregate category field, but I wonder if there is a more efficient way?

P.S. Feel free to criticize my code because I just started my Go journey, I'm not sure about everything :)

1 Answers

The error states that the category is an array instead of just a string.

Your current definition:

type Post struct {
    ID          primitive.ObjectID       `json:"_id" bson:"_id,omitempty"`
    Title       *string                  `json:"title" bson:"title"`
    Slug        *string                  `json:"slug" bson:"slug"`
    Content     []map[string]interface{} `json:"content" bson:"content,omitempty"`
    Category    *string                  `json:"category" bson:"category,omitempty"`
}

Should look like:

type Post struct {
    ID          primitive.ObjectID       `json:"_id" bson:"_id,omitempty"`
    Title       *string                  `json:"title" bson:"title"`
    Slug        *string                  `json:"slug" bson:"slug"`
    Content     []map[string]interface{} `json:"content" bson:"content,omitempty"`
    Category    []*string                  `json:"category" bson:"category,omitempty"`
}

Where Category []*string might still need some tweaking: The pointer to string could also just be a string.

(Not knowing this return from Mongo and not having one running to test):

Another option is that the category is a byte array, and that the type has to be []byte.

Related