【问题标题】:How to project specific fields from a document inside an array?如何从数组内的文档中投影特定字段?
【发布时间】:2016-02-23 05:38:19
【问题描述】:

这是一个典型的文档

{
   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.  

说清楚,我想在没有聚合框架的情况下完成这个

【问题讨论】:

  • 这是预期的行为。您应该考虑编辑您的问题以显示具有预期结果的示例文档。
  • 根据docs,如果没有聚合框架,您将无法做到这一点。
  • 我将切换到 agg 框架,我只是弃权,因为它的计算量更大,这是我应用程序的核心部分。谢谢
  • 在我的示例中我没有使用$elemMatch - 也许这就是我可以在数组上使用投影的原因。但我不得不省略$。我的投影看起来像这样var projection = {'places.name': 1, 'places.location' : 1};。在 MongoDB 3.4 中测试

标签: mongodb mongoose mongodb-query aggregation-framework


【解决方案1】:

你做错了。根据documentation

投影文档中只能出现一个位置$ 运算符。

但是你仍然需要使用$ 操作符才能得到预期的结果:

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 运算符,请改用 "dot notation"


现在,如果您想要的是数组中每个子文档的“名称”和“位置”数组,那么聚合就是要走的路。

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

【讨论】:

    【解决方案2】:

    对于数组中的字段,可以像嵌入对象一样投影它们
    var projection = {'places.name': 1, 'places.location' : 1};
    查看此指南
    https://docs.mongodb.com/manual/reference/operator/aggregation/project/#include-specific-fields-from-embedded-documents

    【讨论】:

      猜你喜欢
      • 2014-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-03
      • 1970-01-01
      • 2021-04-16
      • 1970-01-01
      相关资源
      最近更新 更多