Mgo 如何在嵌套数组中查找嵌套文档?
Mgo how to find nested document inside nested arrays?
下面我设计的文档结构如下:
type MIS_Course struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string `bson:"crse_name"`
}
type MIS_Department struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string `bson:"dept_name"`
Courses []MIS_Course `bson:"crse_list"`
}
type MIS_School struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string `bson:"school_name"`
Departments []MIS_Department `bson:"dept_list"`
}
并且在初始化时,我会在学校的海洋中有一个 "School ABC",其中包含如下所示的内容:
{
"_id" : ObjectId("55fbb522022aae7b3a000003"),
"school_name" : "School ABC",
"dept_list" : [
{
"dept_name" : "Department A",
"crse_list" : [
{
"crse_name" : "Class A"
},
{
"crse_name" : "Class B"
},
]
}
]
}
连续几个小时我都找不到有效的解决方案,因为 school_name、dept_name 和 crse_name:
找到school_name
的dept_list
> 找到dept_name
的crse_list
> 找到crse_name
之所以需要这样的查找链,是因为查找的范围应该限制在学校,然后是部门。逻辑和内务处理发生在发现的每个阶段之后。
我试过
这样的代码
result := MIS_School{}
err := database.C("schools").Find(bson.M{"school_name": school}).Select(
bson.M{"dept_list": bson.M{"$elemMatch": bson.M{"dept_name": dept}}}).Select(
bson.M{"crse_list": bson.M{"$elemMatch": bson.M{"crse_name": crse}}}).One(&result)
但它没有用,因为 Select 不能在 Mgo(?)
中链接投影
我从某处了解到,mongodb 无法直接检索嵌套在深度超过 1-2 层的数组中的文档(在 A 数组中获取 B 数组中的文档 C)。真的吗?我该如何解决这个问题?
谢谢!
您可以链接 Select 语句,但第二次调用的值将覆盖第一次调用的值,而不是按照示例所暗示的那样做,即深入嵌套结构。
要实现您明显想要做的事情,您可以使用聚合框架以任意方式操作这些嵌套对象。
例如,这是一个简单的管道,可以提取完全匹配的课程:
pipeline := []bson.M{
{"$match": bson.M{"school_name": school}},
{"$unwind": "$dept_list"},
{"$unwind": "$dept_list.crse_list"},
{"$match": bson.M{
"dept_list.dept_name": dept,
"dept_list.crse_list.crse_name": crse,
}},
}
iter := coll.Pipe(pipeline).Iter()
您可以像使用 Find 中的迭代器一样使用生成的迭代器。
对于此管道,生成的对象将如下所示:
bson.M{
"_id":"...",
"dept_list": bson.M{
"dept_name": "Department A",
"crse_list": bson.M{
"crse_name": "Class B",
}
},
"school_name":"School ABC",
}
不过,您可以通过任意方式更改生成对象的形状。查看 aggregation framework 文档了解更多详情。
阅读 mongo 文档后,我认为建立嵌套关系的首选方法是使用具有具体化路径的树结构,如 here 在 mongo 上所述。
还有 array of ancestors and parent / child references 的树。看一看。
看起来使用树更简单、更优雅,并且省去了很多技术上的麻烦。
下面我设计的文档结构如下:
type MIS_Course struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string `bson:"crse_name"`
}
type MIS_Department struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string `bson:"dept_name"`
Courses []MIS_Course `bson:"crse_list"`
}
type MIS_School struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string `bson:"school_name"`
Departments []MIS_Department `bson:"dept_list"`
}
并且在初始化时,我会在学校的海洋中有一个 "School ABC",其中包含如下所示的内容:
{
"_id" : ObjectId("55fbb522022aae7b3a000003"),
"school_name" : "School ABC",
"dept_list" : [
{
"dept_name" : "Department A",
"crse_list" : [
{
"crse_name" : "Class A"
},
{
"crse_name" : "Class B"
},
]
}
]
}
连续几个小时我都找不到有效的解决方案,因为 school_name、dept_name 和 crse_name:
找到school_name
的dept_list
> 找到dept_name
的crse_list
> 找到crse_name
之所以需要这样的查找链,是因为查找的范围应该限制在学校,然后是部门。逻辑和内务处理发生在发现的每个阶段之后。
我试过
这样的代码result := MIS_School{}
err := database.C("schools").Find(bson.M{"school_name": school}).Select(
bson.M{"dept_list": bson.M{"$elemMatch": bson.M{"dept_name": dept}}}).Select(
bson.M{"crse_list": bson.M{"$elemMatch": bson.M{"crse_name": crse}}}).One(&result)
但它没有用,因为 Select 不能在 Mgo(?)
中链接投影我从某处了解到,mongodb 无法直接检索嵌套在深度超过 1-2 层的数组中的文档(在 A 数组中获取 B 数组中的文档 C)。真的吗?我该如何解决这个问题?
谢谢!
您可以链接 Select 语句,但第二次调用的值将覆盖第一次调用的值,而不是按照示例所暗示的那样做,即深入嵌套结构。
要实现您明显想要做的事情,您可以使用聚合框架以任意方式操作这些嵌套对象。
例如,这是一个简单的管道,可以提取完全匹配的课程:
pipeline := []bson.M{
{"$match": bson.M{"school_name": school}},
{"$unwind": "$dept_list"},
{"$unwind": "$dept_list.crse_list"},
{"$match": bson.M{
"dept_list.dept_name": dept,
"dept_list.crse_list.crse_name": crse,
}},
}
iter := coll.Pipe(pipeline).Iter()
您可以像使用 Find 中的迭代器一样使用生成的迭代器。
对于此管道,生成的对象将如下所示:
bson.M{
"_id":"...",
"dept_list": bson.M{
"dept_name": "Department A",
"crse_list": bson.M{
"crse_name": "Class B",
}
},
"school_name":"School ABC",
}
不过,您可以通过任意方式更改生成对象的形状。查看 aggregation framework 文档了解更多详情。
阅读 mongo 文档后,我认为建立嵌套关系的首选方法是使用具有具体化路径的树结构,如 here 在 mongo 上所述。
还有 array of ancestors and parent / child references 的树。看一看。
看起来使用树更简单、更优雅,并且省去了很多技术上的麻烦。