Python 从文档中检索单个属性

Python 从文档中检索单个属性,python,mongodb,Python,Mongodb,大家好。 假设我们有一个集合和一个看起来像这样的文档: test_doc = { "ID" : "123", "a" : [ { 'x' : "/", 'y' : "2000", 'z' : "1000" },

大家好。 假设我们有一个集合和一个看起来像这样的文档:

    test_doc = {
    "ID" : "123",
    "a" : [
                    {
                        'x' : "/",
                        'y' : "2000",
                        'z' : "1000"
                    },
                    {
                        'x' : "/var",
                        'y' : "3500",
                        'z' : "3000"
                    }
           ]

      }
db.foo.find({"ID":"123",'a':{$elemMatch:{'x':"/"}}},{_id : 0, 'a.$': 1})
//returns
{ "a" : [ { "x" : "/", "y" : "2000", "z" : "1000" } ] }
db.foo.aggregate( 
        {$match : {"ID":"123"}},  
        {$unwind : "$a"},  
        {$match : {"a.x":"/"}},  
        {$project : {_id : 0, z : "$a.z"}}
)
{ "result" : [ { "z" : "1000" } ], "ok" : 1 }
我需要的是检索单个属性a.z。 在MongoDB中,我使用以下查询:

db.testcol.find({"ID":"123","a.x":"/"},{'a.z':1})
其中返回以下内容:

{ "_id" : ObjectId("skipped"), "a" : [ { "z" : "1000" }, { "z" : "3000" } ] }
如您所见,它返回所有z属性,但当条件为
{“ID”:“123”,“a.x”:“/var”}

所以,问题是:在这种情况下,我如何获得单一财产?这仅仅是一个糟糕的设计问题,还是我应该以某种方式用代码(python)处理返回的文档?任何建议都将不胜感激。

在MongoDB 2.0及更高版本中,这是不可能的。您要做的是返回数组的一个特定元素-但这不是投影实际要做的,它将只返回整个数组,然后返回每个数组的z元素

然而,有了2.2(在写这个答案时是rc2),情况就好了一点。现在,您可以将其用作投影的一部分(有关详细信息,请参见),以便只回拉所需的数组元素。那么,试试这样的方法:

    test_doc = {
    "ID" : "123",
    "a" : [
                    {
                        'x' : "/",
                        'y' : "2000",
                        'z' : "1000"
                    },
                    {
                        'x' : "/var",
                        'y' : "3500",
                        'z' : "3000"
                    }
           ]

      }
db.foo.find({"ID":"123",'a':{$elemMatch:{'x':"/"}}},{_id : 0, 'a.$': 1})
//returns
{ "a" : [ { "x" : "/", "y" : "2000", "z" : "1000" } ] }
db.foo.aggregate( 
        {$match : {"ID":"123"}},  
        {$unwind : "$a"},  
        {$match : {"a.x":"/"}},  
        {$project : {_id : 0, z : "$a.z"}}
)
{ "result" : [ { "z" : "1000" } ], "ok" : 1 }
或者,只需在投影本身中使用$elemMatch,您可能会认为它更干净:

db.foo.find({"ID":"123"},{_id : 0, 'a':{$elemMatch:{'x':"/"}}})
//returns 
{ "a" : [ { "x" : "/", "y" : "2000", "z" : "1000" } ] }
因此,现在,至少返回的数组只包含您想要的条目,您可以简单地引用相关的z元素(子文档上的elemMatch投影还不受支持)

最后但并非最不重要的一点是,在2.2中,我们有一个聚合框架,它可以做的一件事(使用
$project
操作符)是重塑文档并将子文档和数组元素更改为顶级数组。要获得所需的结果,您可以执行以下操作:

    test_doc = {
    "ID" : "123",
    "a" : [
                    {
                        'x' : "/",
                        'y' : "2000",
                        'z' : "1000"
                    },
                    {
                        'x' : "/var",
                        'y' : "3500",
                        'z' : "3000"
                    }
           ]

      }
db.foo.find({"ID":"123",'a':{$elemMatch:{'x':"/"}}},{_id : 0, 'a.$': 1})
//returns
{ "a" : [ { "x" : "/", "y" : "2000", "z" : "1000" } ] }
db.foo.aggregate( 
        {$match : {"ID":"123"}},  
        {$unwind : "$a"},  
        {$match : {"a.x":"/"}},  
        {$project : {_id : 0, z : "$a.z"}}
)
{ "result" : [ { "z" : "1000" } ], "ok" : 1 }
结果如下所示:

    test_doc = {
    "ID" : "123",
    "a" : [
                    {
                        'x' : "/",
                        'y' : "2000",
                        'z' : "1000"
                    },
                    {
                        'x' : "/var",
                        'y' : "3500",
                        'z' : "3000"
                    }
           ]

      }
db.foo.find({"ID":"123",'a':{$elemMatch:{'x':"/"}}},{_id : 0, 'a.$': 1})
//returns
{ "a" : [ { "x" : "/", "y" : "2000", "z" : "1000" } ] }
db.foo.aggregate( 
        {$match : {"ID":"123"}},  
        {$unwind : "$a"},  
        {$match : {"a.x":"/"}},  
        {$project : {_id : 0, z : "$a.z"}}
)
{ "result" : [ { "z" : "1000" } ], "ok" : 1 }

在MongoDB 2.0及更高版本中,这是不可能的。您要做的是返回数组的特定元素-但这不是您的投影实际要做的,它将只返回整个数组,然后返回每个数组的z元素

但是,使用2.2(撰写此答案时为rc2),情况有所好转。您现在可以将其用作投影的一部分(有关详细信息,请参阅),这样您就可以只提取所需的数组元素。因此,请尝试以下操作:

    test_doc = {
    "ID" : "123",
    "a" : [
                    {
                        'x' : "/",
                        'y' : "2000",
                        'z' : "1000"
                    },
                    {
                        'x' : "/var",
                        'y' : "3500",
                        'z' : "3000"
                    }
           ]

      }
db.foo.find({"ID":"123",'a':{$elemMatch:{'x':"/"}}},{_id : 0, 'a.$': 1})
//returns
{ "a" : [ { "x" : "/", "y" : "2000", "z" : "1000" } ] }
db.foo.aggregate( 
        {$match : {"ID":"123"}},  
        {$unwind : "$a"},  
        {$match : {"a.x":"/"}},  
        {$project : {_id : 0, z : "$a.z"}}
)
{ "result" : [ { "z" : "1000" } ], "ok" : 1 }
或者,只需在投影本身中使用$elemMatch,您可能会认为它更干净:

db.foo.find({"ID":"123"},{_id : 0, 'a':{$elemMatch:{'x':"/"}}})
//returns 
{ "a" : [ { "x" : "/", "y" : "2000", "z" : "1000" } ] }
因此,现在,至少返回的数组只包含您想要的条目,您可以简单地引用相关的z元素(子文档上的elemMatch投影还不受支持)

最后但并非最不重要的一点是,在2.2中,我们有一个聚合框架,它可以做的一件事(使用
$project
操作符)是重塑文档并将子文档和数组元素更改为顶级数组。要获得所需的结果,您可以执行以下操作:

    test_doc = {
    "ID" : "123",
    "a" : [
                    {
                        'x' : "/",
                        'y' : "2000",
                        'z' : "1000"
                    },
                    {
                        'x' : "/var",
                        'y' : "3500",
                        'z' : "3000"
                    }
           ]

      }
db.foo.find({"ID":"123",'a':{$elemMatch:{'x':"/"}}},{_id : 0, 'a.$': 1})
//returns
{ "a" : [ { "x" : "/", "y" : "2000", "z" : "1000" } ] }
db.foo.aggregate( 
        {$match : {"ID":"123"}},  
        {$unwind : "$a"},  
        {$match : {"a.x":"/"}},  
        {$project : {_id : 0, z : "$a.z"}}
)
{ "result" : [ { "z" : "1000" } ], "ok" : 1 }
结果如下所示:

    test_doc = {
    "ID" : "123",
    "a" : [
                    {
                        'x' : "/",
                        'y' : "2000",
                        'z' : "1000"
                    },
                    {
                        'x' : "/var",
                        'y' : "3500",
                        'z' : "3000"
                    }
           ]

      }
db.foo.find({"ID":"123",'a':{$elemMatch:{'x':"/"}}},{_id : 0, 'a.$': 1})
//returns
{ "a" : [ { "x" : "/", "y" : "2000", "z" : "1000" } ] }
db.foo.aggregate( 
        {$match : {"ID":"123"}},  
        {$unwind : "$a"},  
        {$match : {"a.x":"/"}},  
        {$project : {_id : 0, z : "$a.z"}}
)
{ "result" : [ { "z" : "1000" } ], "ok" : 1 }

感谢您的快速回答,Adam。实际上我也在考虑$elemMatch,但我对它的工作原理有点困惑。您的回答现在让我明白了。我还添加了一个如何使用聚合框架实现这一点的示例-我需要先测试它,然后才能将其包括在内:)Wow聚合似乎是一个非常简洁的功能。Thx作为示例,非常有用:)感谢您的快速回答,Adam。实际上,我也在考虑$elemMatch,但我对它的工作原理有点困惑。你的回答现在让我明白了。我还添加了一个如何使用聚合框架实现这一点的示例-我需要先测试它,然后才能将其包括在内:)哇,聚合似乎是一个非常好的功能。Thx(对于示例,非常有用:)