【问题标题】:Is there a way to get slice as result of Find()?有没有办法通过 Find() 获得切片?
【发布时间】:2018-08-25 08:27:12
【问题描述】:

现在我在做:

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

有没有更有效的方法可以直接从 Find(或其他搜索功能)获取带有用户名的切片,而无需结构和范围循环?

【问题讨论】:

    标签: mongodb go slice mgo


    【解决方案1】:

    我看不出还有什么比使用appends 的简单range 循环更有效的方法。如果没有所有 Mongo 的东西,你的代码基本上就是这样,而这正是我要做的。

    package main
    
    import (
        "fmt"
    )
    
    type User struct {
        Username string
    }
    
    func main() {
    
        var users []User
        users = append(users, User{"John"}, User{"Jane"}, User{"Jim"}, User{"Jean"})
        fmt.Println(users)
    
        // Interesting part starts here.
        var myUsers []string
        for _, user := range users {
            myUsers = append(myUsers, user.Username)
        }
        // Interesting part ends here.
    
        fmt.Println(myUsers)
    }
    

    https://play.golang.com/p/qCwENmemn-R

    【讨论】:

    • 我的意思是,有没有办法直接从 Find(或其他搜索函数)获取切片,而不需要结构和范围循环?
    【解决方案2】:

    MongoDB find() 的结果始终是文档列表。所以如果你想要一个值列表,你必须像你一样手动转换它。

    使用自定义类型(派生自string

    另请注意,如果您要创建自己的类型(派生自 string),则可以覆盖其解组逻辑,并仅从文档中“提取”username

    这就是它的样子:

    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
    }
    

    然后将用户名查询成一个切片:

    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)
    

    请注意,[]Username[]string 不同,因此这对您来说可能不够,也可能不够。如果您在处理结果时需要将用户名作为值string 而不是Username,您可以简单地将Username 转换为string

    使用Query.Iter()

    避免切片复制的另一种方法是调用Query.Iter(),迭代结果并手动提取和存储username,类似于上述自定义解组逻辑的方式。

    这就是它的样子:

    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)
    

    【讨论】:

      猜你喜欢
      • 2014-06-28
      • 2015-02-25
      • 2018-09-02
      • 1970-01-01
      • 2017-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-05
      相关资源
      最近更新 更多