Go中的MongoDB聚合查找(mgo.v2)

MongoDB Aggregate lookup in Go (mgo.v2)

我正在尝试使用mgo包在go(golang)中的一个mongoDB查询中实现$lookup功能。

以下是我的收藏:

资料夹:

1
2
3
4
"_id"    : ObjectId("22222222222222"),
"name"   :"Media",
"level"  : 1,
"userIDs": [ObjectId("4444444444444")]

文件:

1
2
3
4
5
6
"_id"      : ObjectId("11111111111111"),
"title"    :"Media Management",
"body"     : BinData(0,"PvQ6z2NBm4265duo/e2XsYxA5bXKo="),
"level"    : 1,
"folderID" : ObjectId("22222222222222"), // Foreign Key/Field
"userIDs"  : [ObjectId("44444444444444")]

下面是我编写的在外壳程序上成功运行的查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var query = [
{
 "$lookup": {
   "from":        "documents",
   "localField":  "_id",
   "foreignField":"folderID",
   "as":          "documents",
  }
}
 ,{
  "$match": {
     "userIDs": ObjectId("userIdHere"), // filder by a userID
     "level": {$gte: 0},                // filter by a folder level
    },
  }
];

db.folders.aggregate(query).pretty().shellPrint();

如果我在外壳程序上运行此脚本,则会得到所需的结果。基本上,folder集合返回给我,其中包含通过$lookup链接的完整相关的documents。我不在这里包括它,因为这个问题似乎已经太久了。

我试图将此查询转换为mgo能够解析和执行的内容。在下面的代码中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
query := bson.M{
 "$lookup": bson.M{ // lookup the documents table here
 "from":        "documents",
 "localField":  "_id",
 "foreignField":"folderID",
 "as":          "documents",
},
 "$match": bson.M{
   "level":   bson.M{"$gte": user.Level}, // filter by level
   "userIDs": user.ID,                    // filter by user
  },
}

pipe := collection.Pipe(query) // querying the"folders" collection
err := pipe.All(&result)

我总是得到相同的错误:字段(管道)的类型错误3 = 4

如果我理解正确,那是因为它无法正确地将结果解析回$ result对象。我已尽力确保该结构具有所需的确切结构。我还尝试传递一般的[]interface{}和空的bson.M{}对象。仍然收到相同的错误。

以下是我的文件夹结构:

1
2
3
4
5
6
7
8
type Folder struct {
  ID        bson.ObjectId   `json:"id" bson:"_id"`
  Name      string          `json:"name"`
  Level     int             `json:"level"`
  UserIDs   []bson.ObjectId `json:"userIDs" bson:"userIDs"`
  Users     []User          `json:"-" bson:"-"` // doesn't get stored in the database
  Documents []Document      `json:"-" bson:"-"` // doesn't get stored in the database
}

我还删除了$match子句,以查看是否可以从该$lookup查询中完全得到任何东西。但是我仍然遇到同样的错误。

也许mgo软件包不支持$lookup?如果是这样,还有其他方法吗?也许我可以将原始查询文本发送到mongo并接收原始响应并自己解析?


找到了解决方案!

技巧是在切片([]bson.M)中创建查询并稍微更改查询的结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
query := []bson.M{{
 "$lookup": bson.M{ // lookup the documents table here
   "from":        "documents",
   "localField":  "_id",
   "foreignField":"folderID",
   "as":          "documents",
  }},
  {"$match": bson.M{
   "level": bson.M{"$lte": user.Level},
   "userIDs": user.ID,
}}}

pipe := collection.Pipe(query)
err := pipe.All(&folders)

我在mgo的Pipe函数文档中找到了一条线索。 此外,我还必须更改Folders结构中Documents字段的标签,以便mgo对该字段进行推销:

1
2
3
4
5
6
7
8
9
type Folder struct {
  ID        bson.ObjectId   `json:"id" bson:"_id"`
  Name      string          `json:"name"`
  Level     int             `json:"level"`
  UserIDs   []bson.ObjectId `json:"userIDs" bson:"userIDs"`
  Users     []User          `json:"-" bson:"-"` // doesn't get stored in the database
  Documents []Document      // `json:"-" bson:"-" Removed this so that mgo can unmarshal
                            // the documents correctly
}

现在,我只需要找出一种保存Folder时不将Documents字段存储在数据库中的方法。