2015-01-01 34 views
2

我有插入到蒙戈看起来像这样的文档集合:查询文档与不同结构的结果

type Stats struct { 
    UserStatus string `json:"userStatus" bson:"userStatus"` 
    ... a bunch more fields 
} 

type User struct { 
    ID    bson.ObjectId `json:"-" bson:"_id"` 
    LastName   string  `json:"lastName" bson:"lastName"` 
    FirstName  string  `json:"firstName" bson:"firstName"` 
    Role    string  `json:"role" bson:"role"` 
    Tags    []string  `json:"tags" bson:"tags"` 
    ... (a bunch more fields) 
    Stats   UserStats  `json:"stats" bson:"stats"` 
} 

我想查询它来获取特定的报表,所以我尝试这样做:

func UserNameReport() { 
    ... get mongo session, etc. 

    // create struct of just the data I want returned 
    type UserNames struct { 
     LastName   string  `json:"lastName" bson:"lastName"` 
     FirstName  string  `json:"firstName" bson:"firstName"` 
     ... etc 
     UserStats  Stats   `json:"stats" bson:"stats"` 
    } 

    projection := bson.M{"lastName":1, "firstName":1, etc} 
    result := []UserNames{} 
    err := x.Find({query user collection}).Select(projection).All(&result) 
    ... 
} 

这是行得通的 - 我的问题是,我怎样才能从'统计'结构包含一个领域?换句话说, 我基本上是想“投影”是这样的:

projection := bson.M{"lastName":1, ..., "stats.userStatus":1} <-- stats.userStatus doesn't work 
... 
err := x.Find({query user collection}).Select(projection).All(&result) 

我得到了整个“统计”结果中嵌入的结构 - 我如何从子文件中筛选出只有一个场并将其放入结果集?

谢谢!

回答

1

它完美对我来说,用MongoDB的2.6.5

下面的代码:

package main 

import (
    "fmt" 
    "gopkg.in/mgo.v2" 
    "gopkg.in/mgo.v2/bson" 
    "log" 
) 

type Statistics struct { 
    Url string 
    Hits int 
} 

type Person struct { 
    Num int 
    Uuid string 
    Name string 
    Stats []Statistics 
} 

func main() { 

    // Connect to the database 
    session, err := mgo.Dial("localhost") 
    if err != nil { 
     panic(err) 
    } 
    defer session.Close() 

    // Remove people collection if any 
    c := session.DB("test").C("people") 
    c.DropCollection() 

    // Add some data 
    err = c.Insert(
     &Person{1, "UUID1", "Joe", []Statistics{Statistics{"a", 1}, Statistics{"b", 2}}}, 
     &Person{2, "UUID2", "Jane", []Statistics{Statistics{"c", 3}, Statistics{"d", 4}}}, 
     &Person{3, "UUID3", "Didier", []Statistics{Statistics{"e", 5}, Statistics{"f", 6}}}) 
    if err != nil { 
     log.Fatal(err) 
    } 

    result := []Person{} 
    err = c.Find(bson.M{"$or": []bson.M{bson.M{"uuid": "UUID3"}, bson.M{"name": "Joe"}}}).Select(bson.M{"num": 1, "name": 1, "stats.hits": 1}).All(&result) 
    if err != nil { 
     log.Fatal(err) 
    } 

    fmt.Println(result) 
} 

结果:

[{1 Joe [{ 1} { 2}]} {3 Didier [{ 5} { 6}]}] 

...这正是我所期望的。

0

也许这会帮助其他人 - 本质上我试图带一个嵌入文档的文档,并返回一个结果集,就像我会在SQL中执行select a.LastName +','+ a.FirstName as Name一样, b.OtherData本质上有一个不同的'table'/'文档'。

所以,这里是我目前的解决方案 - 尽管喜欢获得更好的(更高性能?)!

我创建了一个新的结构,我使用 'mapstructure' 库

import "github.com/goinggo/mapstructure" 


type Stats struct { 
    UserStatus string `json:"userStatus" bson:"userStatus"` 
    ... a bunch more fields 
} 

type User struct { 
    ID    bson.ObjectId `json:"-" bson:"_id"` 
    LastName   string  `json:"lastName" bson:"lastName"` 
    FirstName  string  `json:"firstName" bson:"firstName"` 
    Role    string  `json:"role" bson:"role"` 
    Tags    []string  `json:"tags" bson:"tags"` 
    ... (a bunch more fields) 
    Stats   UserStats  `json:"stats" bson:"stats"` 
} 


type MyReportItem struct { 
    FirstName string `json:"firstName" jpath:"firstName"` 
    LastName string `json:"lastName" jpath:"lastName"` 
    Status  string `json:"status" jpath:"stats.userStatus"` 
} 

type MyReport struct { 
    Results []MyReportItem `json:"results"` 
} 


func xxxx(w http.ResponseWriter, r *http.Request) { 

    var users MyReportItem 

    // the results will come back as a slice of map[string]interface{} 
    mgoResult := []map[string]interface{}{} 

    // execute the query 
    err := c.Find(finder).Select(projection).All(&mgoResult) 
    if err != nil { 
     http.Error(w, err.Error(), http.StatusInternalServerError) 
     return 
    } 

    user := MyReportItem{} 
    // iterate through the results and decode them into the MyReport struct 
    for _, x := range mgoResult { 
     docScript, _ := json.Marshal(x) 
     docMap := map[string]interface{}{} 
     json.Unmarshal(docScript, &docMap) 

     err := mapstructure.DecodePath(docMap, &user) 
     if err == nil { 
     users.Results = append(users.Results, user) 
    } 
    } 

    ... send back the results ... 
    _ := json.NewEncoder(w).Encode(&users) 
} 

现在,我得到的对象的切片形式:

results: [ 
    { 
    firstName: "John", 
    lastName: "Doe", 
    status: "active" 
    } 
    ... 
] 

相反的:

{ 
    firstName: "John", 
    lastName: "Doe", 
    stats: { 
      status: "active" 
      } 
}