如何从数组中的文档中投影特定字段?

21
这是一个典型的文档。
{
   title : 'someTitle',
   places : [{name : 'someName', location : 'someLocation'}, {name ...}]
}

我有以下查询

var qs = {title : 'someTitle', places : {$elemMatch : {name : 'someName' } } };

我需要选择一个标题匹配并且其“places”数组中包含名称等于“someName”的文档条目的文档。但问题在于,“places”数组中的条目是大型文档,而我只需要从该文档中获取几个字段。我尝试像这样投影字段,但没有成功。

var projection = {'places.$.name': 1, 'places.$.location' : 1};

这个函数应该返回一个仅包含'name''location'属性的文档数组。

我遇到了以下错误:

Can't canonicalize query: BadValue Cannot specify more than one positional proj. per query.  

为了清晰明确起见,我希望在不使用聚合框架的情况下实现这个目标。

这是预期的行为。您应该考虑编辑您的问题,以显示带有预期结果的示例文档。 - styvane
根据文档,如果没有使用聚合框架,你无法完成这个操作。 - Abdullah Rasheed
我将转换到agg框架,我之前一直避免使用它,因为它需要更多的计算资源,而这是我的应用程序的核心部分。谢谢。 - naughty boy
我在我的示例中没有使用$elemMatch - 也许这就是为什么我可以在数组上使用投影的原因。但是我不得不省略$。我的投影看起来像这样 var projection = {'places.name': 1, 'places.location' : 1};。在MongoDB 3.4中测试过。 - SimonSimCity
2个回答

35

你做错了。根据文档

投影文档中只能出现一个位置标识符 $ 操作符。

但是你仍然需要使用$ 操作符来获得期望的结果:

var qs = { title : 'someTitle', 'places.name' : 'someName' };
var projection = {'places.$': 1 };
db.collection.find(qs, projection);

返回:

{
        "_id" : ObjectId("564f52d7d9a433df958b5630"),
        "places" : [
                {
                        "name" : "someName",
                        "location" : "someLocation"
                }
        ]
}

此外,此处不需要使用$elemMatch运算符,而是应使用"点符号"


如果您想获取数组中每个子文档的"name"和"location"数组,则应使用聚合查询。

db.collection.aggregate([
    { '$match': { 
        'title' : 'someTitle', 
        'places.name' : 'someName' 
    }}, 
    { '$project': { 
        'places': {
            '$map': { 
                'input': '$places', 
                'as': 'place', 
                'in': { 
                    'name': '$$place.name', 
                    'location': '$$place.location'
                }
            }
        }
    }}
])

其结果为:

{
    "_id" : ObjectId("564f52d7d9a433df958b5630"),
    "places" : [
            {
                    "name" : "someName",
                    "location" : "someLocation"
            },
            {
                    "name" : "bar",
                    "location" : "foo"
            }
    ]
}

13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接