douqianke7467 2015-09-18 12:35
浏览 68
已采纳

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

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!

  • 写回答

2条回答 默认 最新

  • doudaifu6083 2015-09-18 19:20
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 一道python难题
  • ¥15 用matlab 设计一个不动点迭代法求解非线性方程组的代码
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试
  • ¥20 问题请教!vue项目关于Nginx配置nonce安全策略的问题
  • ¥15 教务系统账号被盗号如何追溯设备
  • ¥20 delta降尺度方法,未来数据怎么降尺度