dongyisa6254 2018-03-16 10:02
浏览 60
已采纳

有没有一种方法可以通过Find()获得切片?

Now I'm doing:

sess := mongodb.DB("mybase").C("mycollection")
var users []struct {
    Username string `bson:"username"`
}

err = sess.Find(nil).Select(bson.M{"username": 1, "_id": 0}).All(&users)
if err != nil {
    fmt.Println(err)
}

var myUsers []string
for _, user := range users{
    myUsers = append(myUsers, user.Username)
}

Is there a more effective way to get slice with usernames from Find (or another search function) directly, without struct and range loop?

  • 写回答

2条回答 默认 最新

  • dongzhang3482 2018-03-16 11:27
    关注

    The result of a MongoDB find() is always a list of documents. So if you want a list of values, you have to convert it manually just as you did.

    Using a custom type (derived from string)

    Also note that if you would create your own type (derived from string), you could override its unmarshaling logic, and "extract" just the username from the document.

    This is how it could look like:

    type Username string
    
    func (u *Username) SetBSON(raw bson.Raw) (err error) {
        doc := bson.M{}
        if err = raw.Unmarshal(&doc); err != nil {
            return
        }
        *u = Username(doc["username"].(string))
        return
    }
    

    And then querying the usernames into a slice:

    c := mongodb.DB("mybase").C("mycollection") // Obtain collection
    
    var uns []Username
    err = c.Find(nil).Select(bson.M{"username": 1, "_id": 0}).All(&uns)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(uns)
    

    Note that []Username is not the same as []string, so this may or may not be sufficient to you. Should you need a user name as a value of string instead of Username when processing the result, you can simply convert a Username to string.

    Using Query.Iter()

    Another way to avoid the slice copying would be to call Query.Iter(), iterate over the results and extract and store the username manually, similarly how the above custom unmarshaling logic does.

    This is how it could look like:

    var uns []string
    it := c.Find(nil).Select(bson.M{"username": 1, "_id": 0}).Iter()
    defer it.Close()
    for doc := (bson.M{}); it.Next(&doc); {
        uns = append(uns, doc["username"].(string))
    }
    if err := it.Err(); err != nil {
        fmt.Println(err)
    }
    fmt.Println(uns)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?