Mgo如何在嵌套数组中查找嵌套文档?

huangapple go评论74阅读模式
英文:

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_namedept_namecrse_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)

但是它没有起作用,因为在Mgo中无法链式使用Select投影(?)

我从某个地方读到,MongoDB不能直接检索嵌套在数组中超过1-2层的文档(获取A数组内的B数组内的C文档)。这是真的吗?我该如何解决这个问题?

谢谢!

英文:

Here below I have document structure designed as follows:

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"`
}

And when initialized, I would have a "School ABC" in a sea of schools containing something that looks like below:

{
	"_id" : ObjectId("55fbb522022aae7b3a000003"),
	"school_name" : "School ABC",
	"dept_list" : [
		{
			"dept_name" : "Department A",
			"crse_list" : [
				{
					"crse_name" : "Class A"
				},
                {
					"crse_name" : "Class B"
				},
			]
		}
	]
}

For hours on end I couldn't find a solution that effectively works by given the school_name, dept_name, and crse_name:

Find the dept_list of school_name > find the crse_list of dept_name > find crse_name

The reason that such chain of finds are required is because the scope of the find should be limited to the school, and then the department. Logic and housekeeping happens after the each stages of finds.

I tried code such as

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)

But it didn't work since Select projections can't be chained in Mgo(?)

I have read from somewhere that mongodb doesn't have the capability to directly retrieve documents nested in arrays deeper than 1-2 levels (Getting Document C inside B array inside A array). Is that true? How could I work around this problem?

Thanks!

答案1

得分: 2

您可以链接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",
    }

您可以以任意方式更改结果对象的形状。有关更多详细信息,请参阅聚合框架文档。

英文:

You can chain the Select statements, but the value of the second call will override the value of the first call, rather than doing what the example implies it does, which is to dive deeper into the nested structure.

To achieve what apparently you are trying to do, you may use the aggregation framework to manipulate these nested objects in arbitrary ways.

For example, this is a simple pipeline that would pull out the exact matching courses:

    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()

You can use the resulting iterator the same way you use iterators from Find.

For this pipeline, the resulting objects will look like:

    bson.M{
            "_id":"...",
            "dept_list": bson.M{
                    "dept_name": "Department A",   
                    "crse_list": bson.M{
                            "crse_name": "Class B",
                    }
            },
            "school_name":"School ABC",
    }

You can change the shape of the resulting object in arbitrary ways, though. Have a look at the aggregation framework documentation for more details.

答案2

得分: 0

阅读了Mongo文档后,我认为处理嵌套关系的首选方法是使用树结构,并使用材料化路径进行描述,具体描述可以在这里找到。

还有一种可用的树结构是祖先数组父/子引用。你可以看一下。

使用树结构似乎更简单、更优雅,并且可以节省很多技术麻烦。

英文:

After reading the mongo docs I think the preferred way to do nested relationship is to use tree structures with materialized paths as described here on mongo.

Also available are trees of array of ancestors and parent / child references. Take a look.

It seems using trees is simpler, more elegant, and saves a lot of technical hassle.

huangapple
  • 本文由 发表于 2015年9月18日 20:35:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/32652182.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定