使用MongoDB和Golang

时间:2018-01-09 08:06:52

标签: mongodb go mgo

我有以下结构。我使用 Golang 1.9.2

// EventBoost describes the model of a EventBoost
type EventBoost struct {
  ID          string    `bson:"_id" json:"_id" valid:"alphanum,printableascii"`
  CampaignID  string    `bson:"_campaign_id" json:"_campaign_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"`
}

// LocationBoost describes the model of a LocationBoost
type LocationBoost struct {
  ID          string    `bson:"_id" json:"_id" valid:"alphanum,printableascii"`
  CampaignID  string    `bson:"_campaign_id" json:"_campaign_id" valid:"alphanum,printableascii"`
  Name        string    `bson:"name" json:"name"`
  Description string    `bson:"description" json:"description"`
  Level       string    `bson:"level" json:"level"`
  LocationID  string    `bson:"_location_id" json:"_location_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"`
}

// Campaign describes the model of a Campaign
type Campaign struct {
    ID               string           `bson:"_id" json:"_id" valid:"alphanum,printableascii"`
    Name             string           `bson:"name" json:"name"`
    Description      string           `bson:"description" json:"description"`
    EventBoostIDs    []string         `bson:"event_boost_ids" json:"event_boost_ids"`
    LocationBoostIDs []string         `bson:"location_boost_ids" json:"location_boost_ids"`
    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"`
}

广告系列(了解营销广告系列)由活动地理位置构成,可以通过级别(基本或高级)提升。广告系列包含开始日期和结束日期,因此请进行提升。

函数GetEventLevel必须返回给定事件的级别。

// GetEventLevel of an event
func (dao *campaignDAO) GetEventLevel(eventID string) (string, error) {
}

如果活动广告系列isPublishedtrue),并且提升已激活({{1} } {是isPublished)和现在日期介于提升的开始日期和结束日期之间,然后我的事件提升,因此该函数返回级别(基本或高级)。否则,它返回true

我的问题是:我可以用Mongo完全做到这一点吗?或者我是否需要使用Golang在DAO中执行一些逻辑?

如果我能用Mongo做到这一点,我希望,我不知道该怎么做。根据我的理解,我首先需要查找活动和活动的位置,然后在其中搜索日期,但是..

2 个答案:

答案 0 :(得分:3)

在MongoDB中可以轻松完成所需内容的大多数(以及最难的部分)。返回“基本”,“高级”或“标准”的最后一步也很有可能,但我认为这不值得麻烦,因为在Go中这是微不足道的。

在MongoDB中使用Aggregation framework。这可以通过Collection.Pipe()方法在mgo包中找到。您必须将切片传递给它,每个元素对应一个聚合阶段。请阅读此答案以获取更多详细信息:How to Get an Aggregate from a MongoDB Collection

回到你的例子。您的GetEventLevel()方法可以像这样实现:

func (dao *campaignDAO) GetEventLevel(eventID string) (string, error) {
    c := sess.DB("").C("eventboosts") // sess represents a MongoDB Session
    now := time.Now()
    pipe := c.Pipe([]bson.M{
        {
            "$match": bson.M{
                "_event_id":    eventID,            // Boost for the specific event
                "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":         "campaigns",
                "localField":   "_campaign_id",
                "foreignField": "_id",
                "as":           "campaign",
            },
        },
        {"$unwind": "$campaign"},
        {
            "$match": bson.M{
                "campaign.is_published": true,      // Attached campaign is active
            },
        },
    })

    var result []*EventBoost
    if err := pipe.All(&result); err != nil {
        return "", err
    }
    if len(result) == 0 {
        return "standard", nil
    }
    return result[0].Level, nil
}

如果您最多只需要一个EventBoost(或者同时可能不会有更多内容),请使用$limit阶段将结果限制为一个,并使用$project仅获取level字段,仅此而已。

将此管道用于上述简化/优化:

pipe := c.Pipe([]bson.M{
    {
        "$match": bson.M{
            "_event_id":    eventID,            // Boost for the specific event
            "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":         "campaigns",
            "localField":   "_campaign_id",
            "foreignField": "_id",
            "as":           "campaign",
        },
    },
    {"$unwind": "$campaign"},
    {
        "$match": bson.M{
            "campaign.is_published": true,      // Attached campaign is active
        },
    },
    {"$limit": 1},             // Fetch at most 1 result
    {
        "$project": bson.M{
            "_id":   0,        // We don't even need the EventBoost's ID
            "level": "$level", // We do need the level and nothing more
        },
    },
})

答案 1 :(得分:0)

由于您只是将ID存储到其他集合中的引用文档,而不是完全取消对数据的规范化,不是,您不能完全在MongoDB中执行此操作。 MongoDB不是关系数据库。您所描述的正是MongoDB设计的要做的事情。

你需要在Go中执行逻辑;你是否在DAO中这样做取决于你,但就个人而言,我会倾向于根据字段值动态执行逻辑的类型的简单方法,例如: Campaign.GetEventLevel或类似的东西。在DAO中使用细粒度的方法对我来说意味着一些不太适合MongoDB模型的不寻常的设计决策。在大多数情况下,使用MongoDB,您需要检索文档(对象)并在应用程序中使用它们。尝试在MongoDB中执行查询逻辑就像使用典型的RDBMS一样,这将导致挫败感和糟糕的性能。