4

1条记录(一个社区)的表示:

{
    "_id" : ObjectId("538a4734d6194c0e98000001"),
    "name" : "Darko",
    "description" : "Darko",
    "subdomain" : "darko",
    "domain" : "forum.dev",
    "created" : ISODate("2014-05-31T21:18:44.764Z"),
    "category" : "Art and Culture",
    "owner" : "53887456d6194c0f5b000001",
    "members" : [ 
        "53887456d6194c0f5b000001"
    ]
}

和 Go 类型

Community struct {
    Id          bson.ObjectId `bson:"_id,omitempty" json:"id"`
    Name        string        `json:"name"`
    Description string        `bson:",omitempty" json:"description"`
    Subdomain   string        `bson:",omitempty" json:"subdomain"`
    Domain      string        `json:"domain"`
    Created     time.Time     `json:"created"`
    Category    string        `json:"category"`
    Owner       string        `json:"owner"`
    Banned      []string      `bson:",omitempty" json:"banned"`
    Members     []string      `json:"members"`
    Moderators  []string      `bson:",omitempty" json:"moderators"`
    Admins      []string      `bson:",omitempty" json:"admins"`
    Logo        string        `bson:",omitempty" json:"logo"`
    Stylesheets []string      `bson:",omitempty" json:"stylesheets"`
    Javascripts []string      `bson:",omitempty" json:"javascripts"`
}

好的,现在我想检索所有社区的列表,并按js 或GoCategory Art and Culture中的成员数量排序。members.lengthlen(Community.Members)

就像是SELECT * FROM communities ORDER BY COUNT(members) WHERE category = 'Art and Culture'

我有一个要填充或解组的自定义类型

CommunityDirectory struct {
    Id          bson.ObjectId `bson:"_id,omitempty" json:"id"`
    Name        string        `json:"name"`
    Description string        `bson:",omitempty" json:"description"`
    Subdomain   string        `bson:",omitempty" json:"subdomain"`
    Domain      string        `json:"domain"`
    Created     time.Time     `json:"created"`
    Category    string        `json:"category"`
    Logo        string        `bson:",omitempty" json:"logo"`
    Membercount int64         `bson:"membercount" json:"membercount"`
}

到目前为止我所拥有的

func (ctx *CommunityContext) Directory() {
    pipe := ccommunity.Pipe([]bson.M{bson.M{"membercount": bson.M{"$size": "members"}}})
    iter := pipe.Iter()
    result := CommunityDirectory{}
    results := []CommunityDirectory{}
    for {
        if iter.Next(&result) {
            results = append(results, result)
            fmt.Println(result)
        } else {
            break
        }
    }
    ctx.JSON(results)
}

但这不起作用,因为

db.communities.aggregate(
[
{"membercount": {$size:"members"}}
]
)

Error("Printing Stack Trace")@:0
()@src/mongo/shell/utils.js:37
([object Array])@src/mongo/shell/collection.js:866
@(shell):3

uncaught exception: aggregate failed: {
    "errmsg" : "exception: Unrecognized pipeline stage name: 'membercount'",
    "code" : 16436,
    "ok" : 0
}

因此,它应该找到所有,按成员计数排序并分配一个新的“虚拟”字段成员计数,但仅限于“艺术和文化”类别。

我发现 MongoDB 在这方面相当复杂。

  1. mongodb 查询是什么样的?

  2. 这在 Go/mgo 中是什么样子的?

4

1 回答 1

9

当您不熟悉聚合框架时,需要习惯一些概念

在 shell 中工作的管道的正确形式应该是这样的:

db.communties.aggregate([

    // Match the documents first to filter and possibly make use of an index
    { "$match": {
        "category": "Art and Culture"
    }},

    // You include all fields when adding another and you want all
    { "$project": {
        "name": 1,
        "description": 1,
        "subdomain": 1,
        "domain": 1,
        "created": 1,
        "category": 1,
        "owner": 1,
        "members": 1,
        "memberCount": { "$size": "$members" }
    }},

    // $sort means "ORDER BY" in this case the ascending
    { "$sort": { "memberCount": 1 } },

    // Optionally project just the fields you need in the result
    { "$project": {
        "name": 1,
        "description": 1,
        "subdomain": 1,
        "domain": 1,
        "created": 1,
        "category": 1,
        "owner": 1,
        "members": 1
    }}
])

因此,除非您根本不想改变结构,否则确实没有直接等效于“SELECT *”。在这里您需要添加一个字段“memberCount”,因此您需要指定所有字段。您可以使用$$ROOTwhich 复制文档中的所有字段,但您需要将其分配给 中的另一个字段/属性$project,例如:

{ "$project": {
    "_id": "$$ROOT",
    "memberCount": 1
 }}

但是现在当然,您所有的“字段”都与它们原来的不完全相同,并且都以_id.. 但这是个人品味的问题。

接下来要习惯的就是总是$match先尝试使用。这不仅有助于减少在聚合管道的其余部分上操作的文档,而且也是您使用索引来优化查询的唯一机会。一旦你用其他阶段修改了文档,使用索引就结束了,因为它不再是被索引的原始源。实际上与 SQL 并没有什么不同,但语义在您指定的方式上有所不同。请记住,“管道”就像 Unix 的“管道”|运算符一样,所以首先进行“匹配”。

排序有它自己的管道阶段。因此,使用$sort管道阶段的运算符来执行此操作。

决赛$project是可选的。在这里,我们只是丢弃了用于“排序”的“memberCount”字段。


mGo 的用法应该是这样的:

pipeline := [].bson.D{
    bson.M{"$match": bson.M{ "category": "Art and Culture" } },

    bson.M{"$project": bson.M{
        "name": 1,
        "description": 1,
        "subdomain": 1,
        "domain": 1,
        "created": 1,
        "category": 1,
        "owner": 1,
        "members": 1,
        "memberCount": bson.M{ "$size": "$members" }
    }},

    bson.M{ "$sort": bson.M{ "memberCount": 1 } },

    bson.M{ "$project": bson.M{
        "name": 1,
        "description": 1,
        "subdomain": 1,
        "domain": 1,
        "created": 1,
        "category": 1,
        "owner": 1,
        "members": 1
    }}
}

pipe := ccommunity.Pipe( pipeline )

因此,与您会发现的大多数示例的形式确实没有什么不同。

可能查看核心文档中提供的SQL 到聚合映射图表,以了解其他常见 SQL 查询示例,因为它们适用于聚合管道。

于 2014-06-02T00:54:17.573 回答