MongoDB聚合:$project

$project聚合阶段可将输入文档根据请求的字段输出到管道的下个阶段,输出的字段可以是输入文档中的字段,也可以是新的计算字段。

语法

{ $project: { <specification(s)> } }

$project聚合接受一个文档参数,可以指定包含的字段,抑制_id字段,添加新的字段以及重置已有字段的值等。亦或者,也可以指定排除的字段。

$project的参数字段可以是下面的形式:

参数字段形式 描述
<字段>:<1或true> 指定包含的字段,非0整数也被视为true
_id:<0或false> 指定抑制_id字段,也就是_id字段不会被传递到下个阶段。也可以使用REMOVE变量和条件排除字段
<字段>:<表达式> 添加一个新字段或者重置已有字段的值。如果表达式的值为$$REMOVE,则字段被排除
<字段>:<0或false> 排除一个指定的字段。可以使用REMOVE变量和条件排除字段,如果排除_id以外的字段,则不能同时使用其他形式,但是REMOVE变量条件排除字段除外

使用

包含现有字段

  • _id字段默认输出,如果要包含其他字段,必须明确的指定。
  • 如果指定要包含的字段在输入文档中不存在,$project将忽略该字段,输出文档中也不会包含该字段。

抑制_id字段

缺省情况下输出文档包含_id字段,如果不想让_id字段出现在输出文档中必须显示的指定抑制_id字段。

排除字段

如果指定了排除字段,没有被指定的字段默认输出到下个阶段。

{ $project: { "": 0, "": 0, ... } } // 将返回所有没有被指定的字段

如果指定了排除_id字段以外的其他字段,则不能再使用其他形式来指定字段,也就是说这种情况下不能再指定包含其他字段,也不能指定新的字段或重置已有字段。但可以使用REMOVE变量条件排除字段。

条件排除字段

可以使用REMOVE变量根据表达式条件抑制一个字段。

添加字段或重置已有字段

**注意:**也可以使用$addFields来为文档添加字段。

要添加一个字段或重置已有字段的值,可以指定字段名并使用表达式指定值

字面量值

要将字段值直接设置为数字或布尔字面量,而不是将字段设置为解析为字面量的表达式,可使用$literal操作符。否则,$project将把数字或布尔字面量视为包含或排除字段的标志。

修改字段名

通过指定一个新字段并将其值设置为现有字段的字段路径,可以重命名一个字段。

新增数组字段

$project阶段支持使用方括号[]直接创建新的数组字段,如果指定的数组字段在文档中不存在,则操作会将空值替换为该字段的值。

内嵌文档字段

当重塑、添加或重置内嵌文档的字段时,可以使用点号或嵌套字段:

点号形式:

"contact.address.country": <1 or 0 or 表达式>

嵌套字段形式:

contact: { address: { country: <1 or 0 or 表达式> } }

当使用嵌套字段时,不能在嵌套文档内部使用点号指定字段,如下面的就是错误的方式:

contact: { "address.country": <1 or 0 or 表达式> }
内嵌文档字段的路径冲突错误

不能在同一投影中同时指定嵌入文档和嵌入文档中的字段。下面的$project阶段有路径冲突错误,因为试图同时重塑内嵌文档contactcontact.address.country字段:

{ $project: { contact: 1, "contact.address.country": 1 } }

这种错误与父文档和内嵌字段的顺序无关,下面的$project是同样的错误:

{ $project: { "contact.address.country": 1, contact: 1 } }
$project阶段的位置

当使用$project截断式,通常情况下它应该放在管道的最后阶段,用它来指定返回给客户端的字段。

没有必要为了减少传递到后续管道的字段数量而把$project阶段放在管道的开始或中间,这也不太可能提高性能,数据库会自动执行这种优化。

限制

  • $project制定一个空文档会返回错误。
  • $project阶段中不能使用数组下标。

举例

输出文档中包含指定字段

有一个book集合包含下面的文档:

{
  "_id" : 1,
  "title": "abc123",
  "isbn": "0001122223334",
  "author": { "last": "zzz", "first": "aaa" },
  "copies": 5
}

经过下面的$project阶段处理后,输出文档中只包含_idtitleauthor字段。

db.books.aggregate( [ { $project : { title : 1 , author : 1 } } ] )

聚合操作结果:

{ "_id" : 1, "title" : "abc123", "author" : { "last" : "zzz", "first" : "aaa" } }

在输出文档中抑制_id字段

缺省情况下总是包含_id字段,如果要在输出文档中排除_id字段,可以在参数中给_id指定0

books集合中有下面的文档:

{
  "_id" : 1,
  "title": "abc123",
  "isbn": "0001122223334",
  "author": { "last": "zzz", "first": "aaa" },
  "copies": 5
}

经过下面的$project聚合阶段后,_id字段被抑制,输出文档中只有titleauthor字段:

db.books.aggregate( [ { $project : { _id: 0, title : 1 , author : 1 } } ] )

聚合后的结果:

{ "title" : "abc123", "author" : { "last" : "zzz", "first" : "aaa" } }

排除输出文档字段

books集合有下面文档:

{
  "_id" : 1,
  "title": "abc123",
  "isbn": "0001122223334",
  "author": { "last": "zzz", "first": "aaa" },
  "copies": 5,
  "lastModified": "2016-07-28"
}

下面的$peoject阶段排除掉了lastModified字段:

db.books.aggregate( [ { $project : { "lastModified": 0 } } ] )

结果输出:

  "_id" : 1,
  "title": "abc123",
  "isbn": "0001122223334",
  "author": { "last": "zzz", "first": "aaa" },
  "copies": 5

排除内嵌字段

books集合有下面文档:

{
  "_id" : 1,
  "title": "abc123",
  "isbn": "0001122223334",
  "author": { "last": "zzz", "first": "aaa" },
  "copies": 5,
  "lastModified": "2016-07-28"
}

下面的$project阶段排除了输出文档中author.firstlastModified字段:

db.books.aggregate( [ { $project : { "author.first" : 0, "lastModified" : 0 } } ] )

或者,也可以使用字段嵌套来排除字段:

db.bookmarks.aggregate( [ { $project: { "author": { "first": 0}, "lastModified" : 0 } } ] )

这两种方式的结果是等价的:

{
   "_id" : 1,
   "title" : "abc123",
   "isbn" : "0001122223334",
   "author" : {
      "last" : "zzz"
   },
   "copies" : 5,
}

用条件排除字段

可以在聚合表达式中使用REMOVE变量有条件的抑制一个字段。

books集合中有下面的文档:

{
  "_id" : 1,
  "title": "abc123",
  "isbn": "0001122223334",
  "author": { "last": "zzz", "first": "aaa" },
  "copies": 5,
  "lastModified": "2016-07-28"
}
{
  "_id" : 2,
  "title": "Baked Goods",
  "isbn": "9999999999999",
  "author": { "last": "xyz", "first": "abc", "middle": "" },
  "copies": 2,
  "lastModified": "2017-07-21"
}
{
  "_id" : 3,
  "title": "Ice Cream Cakes",
  "isbn": "8888888888888",
  "author": { "last": "xyz", "first": "abc", "middle": "mmm" },
  "copies": 5,
  "lastModified": "2017-07-22"
}

下面的$proejct阶段使用RREMOVE变量排除author.middle值为""的字段:

db.books.aggregate( [
   {
      $project: {
         title: 1,
         "author.first": 1,
         "author.last" : 1,
         "author.middle": {
            $cond: {
               if: { $eq: [ "", "$author.middle" ] },
               then: "$$REMOVE",
               else: "$author.middle"
            }
         }
      }
   }
] )

聚合后的结果:

{ "_id" : 1, "title" : "abc123", "author" : { "last" : "zzz", "first" : "aaa" } }
{ "_id" : 2, "title" : "Baked Goods", "author" : { "last" : "xyz", "first" : "abc" } }
{ "_id" : 3, "title" : "Ice Cream Cakes", "author" : { "last" : "xyz", "first" : "abc", "middle" : "mmm" } }

包含内嵌文档的指定字段

bookmarks有下面的文档:

{ "_id": 1, "user": "1234", "stop": { "title": "book1", "author": "xyz", "page": 32 } }
{ "_id": 2, "user": "7890", "stop": [ { "title": "book2", "author": "abc", "page": 5 }, { "title": "book3", "author": "ijk", "page": 100 } ] }

如果要输出文档中只包含内嵌文档stoptitle字段,可以使用点号或嵌套字段来指定:

用点号指定:

db.bookmarks.aggregate( [ { $project: { "stop.title": 1 } } ] )

用嵌套字段指定:

db.bookmarks.aggregate( [ { $project: { stop: { title: 1 } } } ] )

两种方式是等价的,输出文档如下:

{ "_id" : 1, "stop" : { "title" : "book1" } }
{ "_id" : 2, "stop" : [ { "title" : "book2" }, { "title" : "book3" } ] }

包含计算字段

books集合中有下面的文档:

{
  "_id" : 1,
  "title": "abc123",
  "isbn": "0001122223334",
  "author": { "last": "zzz", "first": "aaa" },
  "copies": 5
}

下面的$project聚合阶段为输出文档添加isbnlastcopiesSold

db.books.aggregate(
   [
      {
         $project: {
            title: 1,
            isbn: {
               prefix: { $substr: [ "$isbn", 0, 3 ] },
               group: { $substr: [ "$isbn", 3, 2 ] },
               publisher: { $substr: [ "$isbn", 5, 4 ] },
               title: { $substr: [ "$isbn", 9, 3 ] },
               checkDigit: { $substr: [ "$isbn", 12, 1] }
            },
            lastName: "$author.last",
            copiesSold: "$copies"
         }
      }
   ]
)

操作返回下面的结果:

{
   "_id" : 1,
   "title" : "abc123",
   "isbn" : {
      "prefix" : "000",
      "group" : "11",
      "publisher" : "2222",
      "title" : "333",
      "checkDigit" : "4"
   },
   "lastName" : "zzz",
   "copiesSold" : 5
}

添加数组字段

一个coll集合有下面的文档:

{ "_id" : ObjectId("55ad167f320c6be244eb3b95"), "x" : 1, "y" : 1 }

下面的操作将字段xy重塑为myArray字段的数组元素:

db.coll.aggregate( [ { $project: { myArray: [ "$x", "$y" ] } } ] )

操作返回下面的结果:

{ "_id" : ObjectId("55ad167f320c6be244eb3b95"), "myArray" : [ 1, 1 ] }

不支持数组下标

不能在$project阶段使用数组下标,请看下面的例子:

创建pizzas集合:

db.pizzas.insert( [
   { _id: 0, name: [ 'Pepperoni' ] },
] )

下面的例子返回披萨:

db.pizzas.aggregate( [
   { $project: { x: '$name', _id: 0 } },
] )

输出结果中包含了披萨:

[ { "x": [ "Pepperoni" ] } ]

下面的例子使用数组下标{$name.0}试图返回一个披萨:

db.pizzas.aggregate( [
   { $project: { x: '$name.0', _id: 0 } },
] )

但是结果中并没有披萨返回:

[ { "x": [] } ]

你可能感兴趣的:(mongodb,mongodb,数据库)