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_namedept_list > 找到dept_namecrse_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 的树。看一看。

看起来使用树更简单、更优雅,并且省去了很多技术上的麻烦。