有没有更好的方法在 mongo 上创建动态匹配?

Is there a better way to create a dynamic match on mongo?

我正在创建一个显示所有类型数据的视图。目前我正在使用大量的 if 语句来实现并为所有不同类型的请求创建一个匹配参数。我真的不认为写出 120 个可能的 if 语句是最好的方法……而且它越来越难以阻止。我希望有人能指出正确的方向。这是我目前所拥有的。

func GetAllHourly(dbsession *mgo.Session, year, month, day, site, size, network, region string, code int) (items []MassAggregation, err error) {
    defer dbsession.Close()
    var match bson.M
    if network == "openx3" {
        network = "openx"
    }

    group := bson.M{"$group": bson.M{"_id": bson.M{"aws_region": "$aws_region", "http_request_status": "$http_request_status", "hour": "$hour", "network": "$network", "site": "$site", "size": "$size", "zone": "$zone", "extra": "$extra"}, "total": bson.M{"$sum": "$count"}}}
    if site == "" && size == "" && network == "" && region == "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day}}
    } else if site != "" && size == "" && network == "" && region == "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site}}
    } else if site != "" && size != "" && network == "" && region == "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size}}
    } else if site != "" && size != "" && network != "" && region == "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}}}
    } else if site != "" && size != "" && network != "" && region != "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region}}
    } else if site != "" && size != "" && network != "" && region != "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region, "http_request_status": code}}
    } else if site == "" && size != "" && network == "" && region == "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size}}
    } else if site == "" && size != "" && network != "" && region == "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}}}
    } else if site == "" && size != "" && network != "" && region != "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region}}
    } else if site == "" && size == "" && network != "" && region == "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}}}
    } else if site == "" && size == "" && network != "" && region != "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region}}
    } else if site == "" && size == "" && network != "" && region != "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region, "http_request_status": code}}
    } else if site == "" && size == "" && network == "" && region != "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "aws_region": region}}
    } else if site == "" && size == "" && network == "" && region != "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "aws_region": region, "http_request_status": code}}
    } else if site == "" && size == "" && network == "" && region == "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "http_request_status": code}}
    } else if site != "" && size == "" && network == "" && region == "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "http_request_status": code}}
    } else if site != "" && size == "" && network == "" && region != "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "aws_region": region}}
    } else if site != "" && size == "" && network != "" && region == "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "network": &bson.RegEx{Pattern: network, Options: "i"}}}
    } else if site == "" && size != "" && network == "" && region == "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "size": size, "http_request_status": code}}
    } else if site == "" && size != "" && network == "" && region != "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "size": size, "aws_region": region}}
    } else if site == "" && size != "" && network != "" && region == "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}}}
    } else if site == "" && size == "" && network != "" && region == "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "http_request_status": code}}
    } else if site == "" && size == "" && network != "" && region != "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region}}
    } else if site != "" && size != "" && network != "" && region == "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "size": size, "http_request_status": code}}
    } else if site != "" && size != "" && network == "" && region == "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size, "http_request_status": code}}
    } else if site == "" && size != "" && network != "" && region == "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "size": size, "http_request_status": code}}
    } else if site != "" && size == "" && network != "" && region != "" && code == -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region, "site": site}}
    } else if site != "" && size == "" && network != "" && region != "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region, "site": site, "http_request_status": code}}
    } else if site != "" && size == "" && network == "" && region != "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "aws_region": region, "site": site, "http_request_status": code}}
    } else if site == "" && size != "" && network != "" && region != "" && code != -1 {
        match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region, "size": size, "http_request_status": code}}
    }

    operations := []bson.M{match, group}
    err = dbsession.DB("logs").C("prod").Pipe(operations).All(&items)
    return
}

如您所见,它不守规矩..但我还没有找到替代方案。我希望我还没有找到答案。

更新: 我稍微改变了我的方法。我仍然很好奇这是否是最好的方法。

func GetAllHourly(dbsession *mgo.Session, year, month, day, site, size, network, region string, code int) (items []MassAggregation, err error) {
    defer dbsession.Close()
    matches := []bson.M{bson.M{"$match": bson.M{"year": year, "month": month, "day": day}}}
    if network == "openx3" {
        network = "openx"
    }

    if site != "" {
        matches = append(matches, bson.M{"$match": bson.M{"site": site}})
    }
    if size != "" {
        matches = append(matches, bson.M{"$match": bson.M{"size": size}})
    }
    if region != "" {
        matches = append(matches, bson.M{"$match": bson.M{"aws_region": region}})
    }
    if code != -1 {
        matches = append(matches, bson.M{"$match": bson.M{"http_request_status": code}})
    }
    if network != "" {
        matches = append(matches, bson.M{"$match": bson.M{"network": &bson.RegEx{Pattern: network, Options: "i"}}})
    }
    group := bson.M{"$group": bson.M{"_id": bson.M{"aws_region": "$aws_region", "http_request_status": "$http_request_status", "hour": "$hour", "network": "$network", "site": "$site", "size": "$size", "zone": "$zone", "extra": "$extra"}, "total": bson.M{"$sum": "$count"}}}
    var operations []bson.M
    for _, match := range matches {
        operations = append(operations, match)
    }
    operations = append(operations, group)
    err = dbsession.DB("logs").C("prod").Pipe(operations).All(&items)
    return
}

bson.M{} 只是 map[string]interface{} 的命名类型,如您在文档中所见:http://godoc.org/labix.org/v2/mgo/bson#M

那么,为什么不将它用作字典来构建自定义查询呢?您将拥有更少的代码:

query := bson.M{}

if site != "" {
       query["site"] = site
    }
    if size != "" {
       query["size"] = size
    }

}

// Then use query variable for querying mongodb