$project (agregação)
Definição
Compatibilidade
Você pode utilizar o $project
para implantações hospedadas nos seguintes ambientes:
MongoDB Atlas: o serviço totalmente gerenciado para implantações do MongoDB na nuvem
MongoDB Enterprise: a versão autogerenciada e baseada em assinatura do MongoDB
MongoDB Community: uma versão com código disponível, de uso gratuito e autogerenciada do MongoDB
Sintaxe
O estágio $project
tem a seguinte forma de protótipo:
{ $project: { <specification(s)> } }
O $project
usa um documento que pode especificar a inclusão de campos, a supressão do campo _id
, a adição de novos campos e a redefinição dos valores de campos existentes. Alternativamente, você pode especificar a exclusão de campos.
As especificações de $project
vêm nos seguintes formatos:
Formato | Descrição |
---|---|
<field>: <1 or true> | Especifica a inclusão de um campo. Números inteiros diferentes de zero também são tratados como true . |
_id: <0 or false> | Especifica a supressão do campo Para excluir um campo condicionalmente, use a variável |
<field>: <expression> | Adiciona um novo campo ou redefine o valor de um campo existente. Se a expressão avaliar para |
<field>: <0 or false> | Especifica a exclusão de um campo. Para excluir um campo condicionalmente, use a variável Se você especificar a exclusão de um campo diferente de Consulte também o estágio |
Comportamento
Incluir campos
O campo
_id
é, por padrão, incluído nos documentos de saída. Para incluir quaisquer outros campos dos documentos de entrada nos documentos de saída, você deve especificar explicitamente a inclusão no$project
.Se você especificar a inclusão de um campo que não existe no documento,
$project
ignorará a inclusão do campo e não o adicionará ao documento.
_id
Campo
Por padrão, o campo _id
é incluído nos documentos de saída. Para excluir o campo _id
dos documentos de saída, você deve especificar explicitamente a supressão do campo _id
em $project
..
Exclua campos
Se você especificar a exclusão de um campo ou campos, todos os outros campos serão são retornados nos documentos de saída.
{ $project: { "<field1>": 0, "<field2>": 0, ... } } // Return all but the specified fields
Se você especificar a exclusão de um campo diferente de _id
, não poderá empregar nenhum outro formulário de especificação $project
, ou seja, se você excluir campos, também não poderá especificar a inclusão de campos, redefinir o valor dos campos existentes nem adicionar novos campos. Esta restrição não se aplica à exclusão condicional de um campo usando a variável REMOVE
.
Consulte também o estágio $unset
para excluir campos.
Excluir campos condicionalmente
Você pode usar a variável REMOVE
em expressões de agregação para suprimir condicionalmente um campo. Para obter um exemplo, consulte Excluir campos condicionalmente.
Adicionar novos campos ou redefinir campos existentes
Observação
O MongoDB stambém fornece $addFields
para adicionar novos campos aos documentos.
Para adicionar um novo campo ou redefinir o valor de um campo existente, especifique o nome do campo e defina seu valor para alguma expressão. Para mais informações sobre expressões, consulte Expressões.
Valores literais
Para definir o valor de um campo diretamente como um literal numérico ou booleano, em vez de definir o campo como uma expressão que se resolve em um literal, use o operador $literal
. Caso contrário, $project
trata o literal numérico ou booleano como sinalizador para incluir ou excluir o campo.
Renomear campo
Ao especificar um novo campo e definir seu valor como o caminho do campo de um campo existente, você pode renomear um campo de forma eficaz.
Novos campos de array
O estágio $project
aceita o uso dos colchetes []
para criar diretamente novos campos de array. Se você especificar campos de array que não existem em um documento, a operação substituirá o null
como o valor desse campo. Para ver um exemplo, consulte Projetar novos campos de array..
Você não pode usar um índice de array com o estágio $project
. Para obter mais informações, consulte Índices de matriz não são compatíveis.
Campos de documento incorporado
Ao projetar ou adicionar/redefinir um campo em um documento incorporado, você pode usar a notação de ponto, como em
"contact.address.country": <1 or 0 or expression>
Ou você pode aninhar os campos:
contact: { address: { country: <1 or 0 or expression> } }
Ao aninhar os campos, você não pode usar a notação de ponto dentro do documento incorporado para especificar o campo, por exemplo contact: {
"address.country": <1 or 0 or expression> }
é inválido.
Erros de colisão de caminho em campos incorporados
Não é possível especificar um documento incorporado e um campo dentro desse documento incorporado na mesma projeção.
O estágio $project
a seguir falha com um erro Path collision
porque tenta projetar o documento contact
incorporado e o campo contact.address.country
:
{ $project: { contact: 1, "contact.address.country": 1 } }
O erro ocorre independentemente da ordem em que o documento principal e o campo incorporado são especificados. O seguinte $project
falha com o mesmo erro:
{ $project: { "contact.address.country": 1, contact: 1 } }
$project
Colocação no palco
Quando você usa um estágio $project
, ele normalmente deve ser o último estágio do pipeline, usado para especificar quais campos devem ser retornados ao cliente.
É improvável que o uso de um estágio $project
no início ou no meio de um pipeline para reduzir o número de campos passados para estágios subsequentes melhore o desempenho, pois o banco de dados executa essa otimização automaticamente.
Considerações
Especificação vazia
O MongoDB retorna um erro se o estágio $project
receber um documento vazio.
Por exemplo, a execução do seguinte pipeline produz um erro:
db.myCollection.aggregate( [ { $project: { } } ] )
índice da matriz
Você não pode usar um índice de array com o estágio $project
. Para obter mais informações, consulte Índices de matriz não são compatíveis.
Exemplos
Incluir campos específicos em documentos de saída
Considere uma coleção books
com o seguinte documento:
{ "_id" : 1, title: "abc123", isbn: "0001122223334", author: { last: "zzz", first: "aaa" }, copies: 5 }
O estágio $project
a seguir inclui apenas os campos _id
, title
e author
nos seus documentos de saída:
db.books.aggregate( [ { $project : { title : 1 , author : 1 } } ] )
A operação resulta no seguinte documento:
{ "_id" : 1, "title" : "abc123", "author" : { "last" : "zzz", "first" : "aaa" } }
Supressão do _id
campo nos documentos de saída
O campo _id
é sempre incluído por padrão. Para excluir o campo _id
dos documentos de saída do estágio $project
, especifique a exclusão do campo _id
definindo-o como 0
no documento de projeção.
Considere uma coleção books
com o seguinte documento:
{ "_id" : 1, title: "abc123", isbn: "0001122223334", author: { last: "zzz", first: "aaa" }, copies: 5 }
O estágio $project
a seguir exclui o campo _id
, mas inclui os campos title
e author
nos seus documentos de saída:
db.books.aggregate( [ { $project : { _id: 0, title : 1 , author : 1 } } ] )
A operação resulta no seguinte documento:
{ "title" : "abc123", "author" : { "last" : "zzz", "first" : "aaa" } }
Excluir campos de documentos de saída
Considere uma coleção books
com o seguinte documento:
{ "_id" : 1, title: "abc123", isbn: "0001122223334", author: { last: "zzz", first: "aaa" }, copies: 5, lastModified: "2016-07-28" }
O estágio $project
a seguir exclui o campo lastModified
da saída:
db.books.aggregate( [ { $project : { "lastModified": 0 } } ] )
Consulte também o estágio $unset
para excluir campos.
Excluir campos de documentos incorporados
Considere uma coleção books
com o seguinte documento:
{ "_id" : 1, title: "abc123", isbn: "0001122223334", author: { last: "zzz", first: "aaa" }, copies: 5, lastModified: "2016-07-28" }
O estágio $project
a seguir exclui os campos author.first
e lastModified
da saída:
db.books.aggregate( [ { $project : { "author.first" : 0, "lastModified" : 0 } } ] )
Como alternativa, você pode aninhar a especificação de exclusão em um documento:
db.bookmarks.aggregate( [ { $project: { "author": { "first": 0}, "lastModified" : 0 } } ] )
Ambas as especificações resultam na mesma saída:
{ "_id" : 1, "title" : "abc123", "isbn" : "0001122223334", "author" : { "last" : "zzz" }, "copies" : 5, }
Consulte também o estágio $unset
para excluir campos.
Excluir campos condicionalmente
Você pode usar a variável REMOVE
em expressões de aggregation para suprimir condicionalmente um campo.
Considere uma coleção books
com o seguinte documento:
{ "_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" }
O estágio $project
a seguir usa a variável REMOVE
para excluir o campo author.middle
somente se ele for igual a ""
:
db.books.aggregate( [ { $project: { title: 1, "author.first": 1, "author.last" : 1, "author.middle": { $cond: { if: { $eq: [ "", "$author.middle" ] }, then: "$$REMOVE", else: "$author.middle" } } } } ] )
A operação de aggregation resulta na seguinte saída:
{ "_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" } }
Dica
Comparação com $addFields
Você pode usar o estágio $addFields
ou $project
para remover campos do documento . A melhor abordagem depende do seu pipeline e de quanto do documento original você deseja reter.
Para ver um exemplo usando $$REMOVE
em um estágio $addFields
, consulte Remover campos.
Incluir campos específicos de documentos incorporados
Considere uma collection bookmarks
com os seguintes documentos:
{ _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 } ] }
Para incluir somente o campo title
no documento incorporado no campo stop
, você pode usar a notação de ponto:
db.bookmarks.aggregate( [ { $project: { "stop.title": 1 } } ] )
Você também pode aninhar a especificação de inclusão em um documento:
db.bookmarks.aggregate( [ { $project: { stop: { title: 1 } } } ] )
Ambas as especificações resultam nos seguintes documentos:
{ "_id" : 1, "stop" : { "title" : "book1" } } { "_id" : 2, "stop" : [ { "title" : "book2" }, { "title" : "book3" } ] }
Incluir campos calculados
Considere uma coleção books
com o seguinte documento:
{ "_id" : 1, title: "abc123", isbn: "0001122223334", author: { last: "zzz", first: "aaa" }, copies: 5 }
O estágio $project
a seguir adiciona os novos campos isbn
, lastName
e copiesSold
:
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" } } ] )
A operação resulta no seguinte documento:
{ "_id" : 1, "title" : "abc123", "isbn" : { "prefix" : "000", "group" : "11", "publisher" : "2222", "title" : "333", "checkDigit" : "4" }, "lastName" : "zzz", "copiesSold" : 5 }
Projetar novos campos de array
Por exemplo, se uma collection incluir o seguinte documento:
{ "_id" : ObjectId("55ad167f320c6be244eb3b95"), "x" : 1, "y" : 1 }
A seguinte operação projeta os campos x
e y
como elementos em um novo campo myArray
:
db.collection.aggregate( [ { $project: { myArray: [ "$x", "$y" ] } } ] )
A operação retorna o seguinte documento:
{ "_id" : ObjectId("55ad167f320c6be244eb3b95"), "myArray" : [ 1, 1 ] }
Se a especificação da array incluir campos que inexistentes em um documento, a operação substituirá null
como valor desse campo.
Por exemplo, considerando o mesmo documento acima, a operação a seguir projeta os campos x
, y
e um campo $someField
inexistente como elementos em um novo campo myArray
:
db.collection.aggregate( [ { $project: { myArray: [ "$x", "$y", "$someField" ] } } ] )
A operação retorna o seguinte documento:
{ "_id" : ObjectId("55ad167f320c6be244eb3b95"), "myArray" : [ 1, 1, null ] }
Índices de array não são compatíveis
Você não pode usar um índice de array com o estágio $project
. Essa seção mostra um exemplo.
Crie a seguinte coleção do pizzas
:
db.pizzas.insert( [ { _id: 0, name: [ 'Pepperoni' ] }, ] )
O exemplo a seguir retorna a pizza:
db.pizzas.aggregate( [ { $project: { x: '$name', _id: 0 } }, ] )
A pizza é retornada na saída do exemplo:
[ { x: [ 'Pepperoni' ] } ]
O exemplo seguinte utiliza um índice de array ($name.0
) para tentar retornar a pizza:
db.pizzas.aggregate( [ { $project: { x: '$name.0', _id: 0 } }, ] )
A pizza não é retornada na saída do exemplo:
[ { x: [] } ]