在mongo中投影子查询

时间:2013-04-20 19:26:08

标签: mongodb mapreduce projection

我正在使用动态表单构建器将值存储到mongo中。这意味着字段是在运行时定义的。

现在我试图让用户构建一个动态的数据网格视图,以便他们可以一目了然地选择要查看的字段。因此,我需要投影存储在集合项中的字段子集。

以下是集合中的2条记录的示例

{
"_id": {
    "$oid": "511ff0a8521e66d41b0d35d6"
},
"FormID": {
    "$uuid": "413ba627-94bf-0ca7-49b3-9ca2a1a3e9b5"
},
"ResultID": {
    "$uuid": "45f455ae-8486-aaa9-b97a-e480bfdf3db4"
},
"FieldValues": [
    {
        "FieldID": "first name",
        "FieldValue": "John"
    },
    {
        "FieldID": "last name",
        "FieldValue": "smith"
    },
    {
        "FieldID": "school",
        "FieldValue": "high school"
    },
    {
        "FieldID": "favorite subject",
        "FieldValue": "math"
    },

]
},

{
"_id": {
    "$oid": "511ff0a8521e66d41b0d35d7"
},
"FormID": {
    "$uuid": "413ba627-94bf-0ca7-49b3-9ca2a1a3e9b5"
},
"ResultID": {
    "$uuid": "45f455ae-8486-aaa9-b97a-e480bfdf3db5"
},
"FieldValues": [
    {
        "FieldID": "first name",
        "FieldValue": "sarah"
    },
    {
        "FieldID": "last name",
        "FieldValue": "smith"
    },
    {
        "FieldID": "school",
        "FieldValue": "high school"
    },
    {
        "FieldID": "favorite subject",
        "FieldValue": "english"
    },

]
},

假设我想投影结果标识,名字,姓氏

在SQL中 - 我会在自己的表中定义FieldValues,我会对Field值进行子查询,其中ResultId =(parent的结果id)和FieldID =“first name”,然后是另一个子查询“姓氏”等等,以平衡结果。

我一直试图弄清楚如何用mongo做到这一点。我能够找到$ slice运算符,但这只能让你获得一组连续的数组元素。

我不想获得整个文档的原因是,在某些情况下,我的客户已经定义了400多个要跟踪的字段。对所有这些甚至200行进行反序列化可能意味着通过网络传递100MB数据并进行反序列化(慢速)。

任何意见/建议都将不胜感激

1 个答案:

答案 0 :(得分:2)

您可以构造适当的聚合框架语法,以准确返回所需内容。它可能不够快,但它会返回您想要的确切格式,而不会将完整的文档拉下来。为了加快速度,我假设您可以避免在整个集合中运行它,方法是让管道的第一阶段为{$match},只选择相关的文档子集(并且该标准应该被编入索引)。

对于字段first namelast name的两个示例文档使用以下管道阶段,您只能返回_id和那些字段。对于一组给定的字段ID,您可以以编程方式生成此管道。

unwind = { "$unwind" : "$FieldValues" };

match = { "$match" : {
        "FieldValues.FieldID" : {
            "$in" : [
                "first name",
                "last name"
            ]
        }
    }
};

proj = { "$project" : {
        "first name" : {
            "$cond" : [
                {
                    "$eq" : [
                        "first name",
                        "$FieldValues.FieldID"
                    ]
                },
                "$FieldValues.FieldValue",
                "  skip"
            ]
        },
        "last name" : {
            "$cond" : [
                {
                    "$eq" : [
                        "last name",
                        "$FieldValues.FieldID"
                    ]
                },
                "$FieldValues.FieldValue",
                "  skip"
            ]
        }
    }
};

group = { "$group" : {
        "_id" : "$_id",
        "first name" : {
            "$max" : "$first name"
        },
        "last name" : {
            "$max" : "$last name"
        }
    }
};

db.project.aggregate(unwind, match, proj, group)
{
    "result" : [
        {
            "_id" : ObjectId("511ff0a8521e66d41b0d35d7"),
            "first name" : "sarah",
            "last name" : "smith"
        },
        {
            "_id" : ObjectId("511ff0a8521e66d41b0d35d6"),
            "first name" : "John",
            "last name" : "smith"
        }
    ],
    "ok" : 1
}