使用不同结构查询结果的文档

时间:2015-01-01 03:48:52

标签: go mgo

我有一组插入Mongo的文档,看起来像这样:

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)

我得到了整个&#34;统计数据&#34;结果中的嵌入式结构 - 如何从子文档中过滤掉一个字段并将其放入结果集中?

谢谢!

2 个答案:

答案 0 :(得分: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}]}]

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

答案 1 :(得分:0)

也许这会对其他人有所帮助 - 实际上我试图用一个嵌入式文档来获取一个文档并返回一个结果集,就像我在SQL中一样,选择a.LastName +&#39;,&#39; + a.FirstName作为名称,b。其他数据,实质​​上有一个不同的表&#39; /&#39;文件&#39;。

所以这是我目前的解决方案 - 喜欢获得更好的(更高效的?)!

我创建了一个新的结构,我使用了#map;地图结构&#39;图书馆

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"
           }
}