My Models
type (
//Category implements item category in database
Category struct {
ID bson.ObjectId `bson:"_id,omitempty" json:"id"`
Name string `bson:"name" json:"name" form:"name" valid:"Required"`
IsActive bool `bson:"is_active" json:"is_active" form:"is_active" valid:"Required"`
Slug string `bson:"slug" json:"slug"`
Icon string `bson:"icon" json:"icon" form:"icon"`
SidebarIcon string `bson:"sidebar_icon" json:"sidebar_icon" form:"sidebar_icon"`
Parent bson.ObjectId `bson:"parent,omitempty" json:"parent,omitempty" form:"parent"`
CreatedAt time.Time `bson:"created_at" json:"-"`
UpdatedAt time.Time `bson:"updated_at" json:"-"`
IsDeleted bool `bson:"is_deleted" json:"-"`
}
)
My get collection query:
categories := []models.Category{}
f := func(collection *mgo.Collection) error {
query := []bson.M{
{
"$match": bson.M{
"is_deleted": bson.M{
"$ne": true,
},
},
},
{
"$sort": bson.M{
orderBy: pipeOrder,
},
},
{
"$limit": limit,
},
{
"$skip": skip,
},
{
"$lookup": bson.M{
"from": "categories",
"localField": "_id",
"foreignField": "parent",
"as": "parentlist",
},
},
}
return collection.Pipe(query).All(&categories)
Goal : retrieve all the category along with their parent if their parent id matches with one of the document inside the collection.
Issue : retrieved all the category but missing 'parentlist' joined attribute
Stack : mgo to interact with DB and golang version 1.8
In your aggregation you lookup the parents and they will be stored in a field called parentlist
. And you try to unmarshal the results into a slice of Category
, but the type Category
has no field that would match parentlist
. So that field will be "lost" during the unmarshaling process.
There are many ways to get the additional parentlist
, some of the possibilities are detailed in this answer: Mgo aggregation: how to reuse model types to query and unmarshal "mixed" results?
One option is to use a wrapper struct like this:
type CategoryWithParents struct {
Category models.Category `bson:",inline"`
Parents []*models.Category `bson:"parentlist"`
}
And unmarshal into a slice of this:
var results []CategoryWithParents
err := collection.Pipe(query).All(&results)
This will get all the parents.
If there may be one parent at most for all categories, you can modify the aggregation to $unwind
the parentlist
, and Parents
may be a single *model.Category
instead of a slice:
type CategoryWithParents struct {
Category models.Category `bson:",inline"`
OptionalParent *models.Category `bson:"parentlist"`
}
var results []CategoryWithParents
f := func(collection *mgo.Collection) error {
query := []bson.M{
{
"$match": bson.M{
"is_deleted": bson.M{
"$ne": true,
},
},
},
{
"$sort": bson.M{
orderBy: pipeOrder,
},
},
{"$limit": limit},
{"$skip": skip},
{
"$lookup": bson.M{
"from": "categories",
"localField": "_id",
"foreignField": "parent",
"as": "parentlist",
},
},
{
"$unwind": bson.M{
"path": "parentlist",
"preserveNullAndEmptyArrays": true,
},
},
}
return collection.Pipe(query).All(&results)
}