有没有办法得到切片作为Find()的结果?

时间:2018-03-16 10:02:08

标签: mongodb go slice mgo

现在我在做:

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(或其他搜索功能)获取用户名切片,而不使用struct和range循环?

2 个答案:

答案 0 :(得分:0)

我不知道哪个比range的简单append循环更有效。如果没有所有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

答案 1 :(得分:0)

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)