I have these two models :
// EventBoost describes the model of a EventBoost
type EventBoost struct {
ID string `bson:"_id" json:"_id" valid:"alphanum,printableascii"`
Name string `bson:"name" json:"name"`
Description string `bson:"description" json:"description"`
Level string `bson:"level" json:"level"`
EventID string `bson:"_event_id" json:"_event_id" valid:"alphanum,printableascii"`
StartDate time.Time `bson:"start_date" json:"start_date"`
EndDate time.Time `bson:"end_date" json:"end_date"`
IsPublished bool `bson:"is_published" json:"is_published"`
CreatedBy string `bson:"created_by" json:"created_by"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
ModifiedAt time.Time `bson:"modified_at" json:"modified_at"`
}
// Event describes the model of an Event
type Event struct {
ID string `bson:"_id" json:"_id" valid:"alphanum,printableascii"`
OldID string `bson:"old_id" json:"old_id" valid:"alphanum,printableascii"`
ParentID string `bson:"_parent_id" json:"_parent_id" valid:"alphanum,printableascii"`
Name string `bson:"name" json:"name"`
Content string `bson:"content" json:"content"`
Slug string `bson:"slug" json:"slug"`
LocationID string `bson:"_location_id" json:"_location_id"`
Price string `bson:"price" json:"price"`
Categories []string `bson:"categories" json:"categories"`
Tags []string `bson:"tags" json:"tags"`
Organisers []string `bson:"organisers" json:"organisers"`
Artists []string `bson:"artists" json:"artists"`
Image string `bson:"image" json:"image"`
IsPublished bool `bson:"is_published" json:"is_published"`
IsProposed bool `bson:"is_proposed" json:"is_proposed"`
CreatedBy string `bson:"created_by" json:"created_by"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
ModifiedAt time.Time `bson:"modified_at" json:"modified_at"`
}
I want, when I lookup an EventBoost, to return only an Event without having to perform the cleaning with Golang logic. Because actually, the documents that are return have a property named event. I directly want have an Event document.
Here is my method that needs to return []*models.Event :
// Boosted returns the boosted events
func (dao *eventBoostDAO) Boosted() ([]*models.Event, error) {
// Clone the session
session := dao.session.Clone()
defer session.Close()
// Get the time
now := time.Now()
// Create the pipe
pipe := session.DB(shared.DatabaseNamespace).C(dao.collection).Pipe([]bson.M{
{
"$match": bson.M{
"is_published": true, // Boost is active
"start_date": bson.M{"$lt": now}, // now is between start and end
"end_date": bson.M{"$gt": now}, // now is between start and end
},
},
{
"$lookup": bson.M{
"from": "events",
"localField": "_event_id",
"foreignField": "_id",
"as": "event",
},
},
})
var result []*models.Event
err := pipe.All(&result)
if err != nil {
return nil, err
}
return result, nil
}
Looking at the Mongo documentation, I found that $project should help me doing what I want, but I did not find how to transform a nested document to the final document.
You may use $unwind
to "transform" the event
array field to a single embedded document, then $replaceRoot
to "promote" this event
field to be the new "root":
pipe := session.DB(shared.DatabaseNamespace).C(dao.collection).Pipe([]bson.M{
{
"$match": bson.M{
"is_published": true, // Boost is active
"start_date": bson.M{"$lt": now}, // now is between start and end
"end_date": bson.M{"$gt": now}, // now is between start and end
},
},
{
"$lookup": bson.M{
"from": "events",
"localField": "_event_id",
"foreignField": "_id",
"as": "event",
},
},
{"$unwind": "$event"},
{"$replaceRoot": bson.M{ "newRoot": "$event" }},
})
This solution handles properly if there are multiple events for a given EventBoost
.