Go - mgo,从集合中检索所有嵌套字段
Go - mgo, retrieve all nested fields from the collection
我有一个按以下方式定义的数据库结构。
{
name: "Jane",
films: [
{
title: "The Shawshank Redemption",
year: "1994"
},
{
title: "The Godfather",
year: "1972"
}
]
},
{
name: "Jack",
films: [
{
title: "12 Angry Men",
year: "1957"
},
{
title: "The Dark Knight",
year: "2008"
}
]
}
我想要 return 所有电影的一部分 - []Film
并且,如果可能的话,在另一个查询中,我想从集合中提取所有影片的一部分 - []string
。我可以拉出整个集合并提取应用程序逻辑中的相关数据,但是是否可以在查询中实现?我试过使用 Select()
方法,像这样:c.Find(nil).Select(<various conditions>).All(&results)
但我没有成功。
我认为这是 mongo
标签上最受欢迎的问题之一。而且我必须说,如果你需要你做错了什么,也许你应该使用 RDBMS 而不是 Mongo,因为这种查询的性能下降将使 Mongo 的无模式功能带来的所有收益无效, "all-in-one" 文件等..
无论如何,答案很简单——你无法随心所欲地获得电影列表。 Mongo 的 find
只能 return 完整或部分顶级文档。我的意思是,使用 db.collection.find({}, {'films': 1})
查询可以获得的最佳结果是
这样的列表
{
films: [
{
title: "The Shawshank Redemption",
year: 1994
},
{
title: "The Godfather",
year: 1972
}
]
},
{
films: [
{
title: "12 Angry Men",
year: 1957
},
{
title: "The Dark Knight",
year: 2008
}
]
}
不是你所期望的,对吧?
获得像
这样的数组的唯一方法
{
title: "The Shawshank Redemption",
year: 1994
},
{
title: "The Godfather",
year: 1972
},
{
title: "12 Angry Men",
year: 1957
},
{
title: "The Dark Knight",
year: 2008
}
就是使用aggregation。
检索电影数组的基本Mongo查询是
db.collection.aggregate([{
$unwind: '$films'
}, {
$project: {
title: '$films.title',
year: '$films.year'
}
}])
此查询的 Go 代码是
package main
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"fmt"
)
func main() {
session, err := mgo.Dial("mongodb://127.0.0.1:27017/db")
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("db").C("collection")
pipe := c.Pipe(
[]bson.M{
bson.M{
"$unwind": "$films",
},
bson.M{
"$project": bson.M{
"title": "$films.title",
"year": "$films.year",
},
},
},
)
result := []bson.M{}
err = pipe.All(&result)
fmt.Printf("%+v", result) // [map[_id:ObjectIdHex("57a2ed6640ce01187e1c9164") title:The Shawshank Redemption year:1994] map[_id:ObjectIdHex("57a2ed6640ce01187e1c9164") title:The Godfather year:1972] map[_id:ObjectIdHex("57a2ed6f40ce01187e1c9165") title:12 Angry Men year:1957] map[year:2008 _id:ObjectIdHex("57a2ed6f40ce01187e1c9165") title:The Dark Knight]]
}
如果您需要 select 顶级文档代码的附加条件
pipe := c.Pipe(
[]bson.M{
bson.M{
"$match": bson.M{
"name": "Jane",
},
},
bson.M{
"$unwind": "$films",
},
bson.M{
"$project": bson.M{
"title": "$films.title",
"year": "$films.year",
},
},
},
)
// result [map[_id:ObjectIdHex("57a2ed6640ce01187e1c9164") title:The Shawshank Redemption year:1994] map[title:The Godfather year:1972 _id:ObjectIdHex("57a2ed6640ce01187e1c9164")]]
如果您需要过滤电影,您可以使用下一个查询
pipe := c.Pipe(
[]bson.M{
bson.M{
"$unwind": "$films",
},
bson.M{
"$project": bson.M{
"title": "$films.title",
"year": "$films.year",
},
},
bson.M{
"$match": bson.M{
"year": bson.M{
"$gt": 2000,
},
},
},
},
)
// result [map[_id:ObjectIdHex("57a2ed6f40ce01187e1c9165") year:2008 title:The Dark Knight]]
聚合的问题是一个简单的事实,即大部分聚合操作不使用索引,并且在大型集合上可能会很慢。这就是为什么我建议您考虑 RDBMS,如果您需要大量聚合,它可能是更好的选择。
并且无法从 mgo
获取 []string
,因为它总是 returns bson.M
(或 []bson.M
),即 map[string]interface{}
.
我有一个按以下方式定义的数据库结构。
{
name: "Jane",
films: [
{
title: "The Shawshank Redemption",
year: "1994"
},
{
title: "The Godfather",
year: "1972"
}
]
},
{
name: "Jack",
films: [
{
title: "12 Angry Men",
year: "1957"
},
{
title: "The Dark Knight",
year: "2008"
}
]
}
我想要 return 所有电影的一部分 - []Film
并且,如果可能的话,在另一个查询中,我想从集合中提取所有影片的一部分 - []string
。我可以拉出整个集合并提取应用程序逻辑中的相关数据,但是是否可以在查询中实现?我试过使用 Select()
方法,像这样:c.Find(nil).Select(<various conditions>).All(&results)
但我没有成功。
我认为这是 mongo
标签上最受欢迎的问题之一。而且我必须说,如果你需要你做错了什么,也许你应该使用 RDBMS 而不是 Mongo,因为这种查询的性能下降将使 Mongo 的无模式功能带来的所有收益无效, "all-in-one" 文件等..
无论如何,答案很简单——你无法随心所欲地获得电影列表。 Mongo 的 find
只能 return 完整或部分顶级文档。我的意思是,使用 db.collection.find({}, {'films': 1})
查询可以获得的最佳结果是
{
films: [
{
title: "The Shawshank Redemption",
year: 1994
},
{
title: "The Godfather",
year: 1972
}
]
},
{
films: [
{
title: "12 Angry Men",
year: 1957
},
{
title: "The Dark Knight",
year: 2008
}
]
}
不是你所期望的,对吧?
获得像
这样的数组的唯一方法{
title: "The Shawshank Redemption",
year: 1994
},
{
title: "The Godfather",
year: 1972
},
{
title: "12 Angry Men",
year: 1957
},
{
title: "The Dark Knight",
year: 2008
}
就是使用aggregation。
检索电影数组的基本Mongo查询是
db.collection.aggregate([{
$unwind: '$films'
}, {
$project: {
title: '$films.title',
year: '$films.year'
}
}])
此查询的 Go 代码是
package main
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"fmt"
)
func main() {
session, err := mgo.Dial("mongodb://127.0.0.1:27017/db")
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("db").C("collection")
pipe := c.Pipe(
[]bson.M{
bson.M{
"$unwind": "$films",
},
bson.M{
"$project": bson.M{
"title": "$films.title",
"year": "$films.year",
},
},
},
)
result := []bson.M{}
err = pipe.All(&result)
fmt.Printf("%+v", result) // [map[_id:ObjectIdHex("57a2ed6640ce01187e1c9164") title:The Shawshank Redemption year:1994] map[_id:ObjectIdHex("57a2ed6640ce01187e1c9164") title:The Godfather year:1972] map[_id:ObjectIdHex("57a2ed6f40ce01187e1c9165") title:12 Angry Men year:1957] map[year:2008 _id:ObjectIdHex("57a2ed6f40ce01187e1c9165") title:The Dark Knight]]
}
如果您需要 select 顶级文档代码的附加条件
pipe := c.Pipe(
[]bson.M{
bson.M{
"$match": bson.M{
"name": "Jane",
},
},
bson.M{
"$unwind": "$films",
},
bson.M{
"$project": bson.M{
"title": "$films.title",
"year": "$films.year",
},
},
},
)
// result [map[_id:ObjectIdHex("57a2ed6640ce01187e1c9164") title:The Shawshank Redemption year:1994] map[title:The Godfather year:1972 _id:ObjectIdHex("57a2ed6640ce01187e1c9164")]]
如果您需要过滤电影,您可以使用下一个查询
pipe := c.Pipe(
[]bson.M{
bson.M{
"$unwind": "$films",
},
bson.M{
"$project": bson.M{
"title": "$films.title",
"year": "$films.year",
},
},
bson.M{
"$match": bson.M{
"year": bson.M{
"$gt": 2000,
},
},
},
},
)
// result [map[_id:ObjectIdHex("57a2ed6f40ce01187e1c9165") year:2008 title:The Dark Knight]]
聚合的问题是一个简单的事实,即大部分聚合操作不使用索引,并且在大型集合上可能会很慢。这就是为什么我建议您考虑 RDBMS,如果您需要大量聚合,它可能是更好的选择。
并且无法从 mgo
获取 []string
,因为它总是 returns bson.M
(或 []bson.M
),即 map[string]interface{}
.