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 |
---|---|
| Especifica a inclusão de um campo. Números inteiros diferentes de zero também são tratados como |
| Especifica a supressão do campo Para excluir um campo condicionalmente, use a |
| Adiciona um novo campo ou redefine o valor de um campo existente. Se a expressão avaliar para |
| Especifica a exclusão de um campo. Para excluir um campo condicionalmente, use a Se você especificar a exclusão de um campo diferente 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 obter mais informações sobre expressões, consulte Operadores de expressão.
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" } }
Suprimir o campo _id
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 manter.
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: [] } ]
Os exemplos de C# nesta página utilizam o banco de dados sample_mflix
a partir dos conjuntos de dados de amostra do Atlas. Para saber como criar um cluster MongoDB Atlas gratuito e carregar os conjuntos de dados de exemplo, consulte Introdução na documentação do driver MongoDB .NET/C#.
As seguintes classes Movie
e ImdbData
modelam os documentos na collection sample_mflix.movies
:
public class Movie { public ObjectId Id { get; set; } public string Title { get; set; } public List<string> Genres { get; set; } public List<string> Directors { get; set; } public List<string> Writers { get; set; } public string Type { get; set; } public string Plot { get; set; } public ImdbData Imdb { get; set; } public List<string> Cast { get; set; } }
public class ImdbData { public string Id { get; set; } public int Votes { get; set; } public float Rating { get; set; } }
Observação
Pacote de Convenções para Caso Pascal
As classes C# nesta página usam maiúsculas e minúsculas Pascal para seus nomes de propriedade , mas os nomes de campo na coleção MongoDB usam camel case. Para contabilizar esta diferença, você pode utilizar o seguinte código para registrar um ConventionPack
quando seu aplicação iniciar:
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);
Para usar o driver MongoDB .NET/C# para adicionar um estágio $project
a um pipeline de agregação , chame o método Project()
em um objeto PipelineDefinition
e passe um objeto ProjectionDefinitionBuilder<TDocument>
. TDocument
é a classe que representa os documentos em sua coleção.
As seções a seguir mostram as diferentes maneiras de personalizar os documentos de saída do estágio $project
.
Incluir campos específicos em documentos de saída
Para incluir campos específicos ao usar o driver .NET/C#, chame o método Include()
no construtor de projeção . Você pode encadear Include()
chamadas para incluir vários campos.
O seguinte exemplo de código produz um documento que inclui somente os campos _id
, plot
e title
:
var pipeline = new EmptyPipelineDefinition<Movie> () .Project( Builders<Movie>.Projection .Include(m => m.Title) .Include(m => m.Plot) ); var result = movieCollection.Aggregate(pipeline).FirstOrDefault();
O pipeline retorna o seguinte documento:
{ "_id" : { "$oid" : "573a1390f29313caabcd42e8" }, "plot" : "A group of bandits stage a brazen train hold-up, only to find a determined posse hot on their heels.", "title" : "The Great Train Robbery" }
Excluir campos de documentos de saída
Para excluir um campo dos documentos de resultado ao usar o driver .NET/C#, chame o método Exclude()
no construtor de projeção . Você pode encadear Exclude()
chamadas para excluir vários campos.
O seguinte exemplo de código produz um documento que exclui o campo Type
:
var pipeline = new EmptyPipelineDefinition<Movie>() .Project( Builders<Movie>.Projection .Exclude(m => m.Type) ); var result = movieCollection.Aggregate(pipeline).FirstOrDefault();
Por padrão, os documentos de resultados sempre incluem o campo _id
. O seguinte exemplo de código produz um documento que exclui o campo _id
, mas inclui os campos plot
e title
:
var pipeline = new EmptyPipelineDefinition<Movie> () .Project( Builders<Movie>.Projection .Exclude(m => m.Id) .Include(m => m.Title) .Include(m => m.Plot) ); var result = movieCollection.Aggregate(pipeline).FirstOrDefault();
O pipeline resulta no seguinte documento:
{ "plot" : "A group of bandits stage a brazen train hold-up, only to find a determined posse hot on their heels.", "title" : "The Great Train Robbery" }
Excluir campos de documentos incorporados
Para excluir um campo em um documento incorporado ao usar o driver .NET/C#, chame o método Exclude()
no construtor de projeção e passe o caminho para a propriedade de classe correspondente. Você pode encadear Exclude()
chamadas para excluir vários campos.
O seguinte exemplo de código produz um documento que exclui os campos imdb.id
e type
:
var pipeline = new EmptyPipelineDefinition<Movie> () .Project( Builders<Movie>.Projection .Exclude("Imdb.id") .Exclude(m => m.Type) ); var result = movieCollection.Aggregate(pipeline).FirstOrDefault();
O pipeline resulta na seguinte saída:
{ "plot" : "A group of bandits stage a brazen train hold-up, only to find a determined posse hot on their heels.", "title" : "The Great Train Robbery" ... "imdb" : { "rating" : 7.4000000000000004, "votes" : 9847 } }
Observação
Usar strings para campos de ID incorporados
Para projeto um campo ID em um documento incorporado, especifique o nome do campo como uma string, não uma expressão lambda.
Excluir campos condicionalmente
Você pode usar a variável REMOVE
em expressões de agregação para suprimir condicionalmente um campo:
var stage = new BsonDocument { { "title", 1 }, { "imdb.id", 1 }, { "imdb.rating", 1 }, { "imdb.votes", new BsonDocument("$cond", new BsonDocument { { "if", new BsonDocument("$eq", new BsonArray { "", "$imdb.votes" }) }, { "then", "$$REMOVE" }, { "else", "$imdb.votes" } }) } }; var pipeline = new EmptyPipelineDefinition<Movie>() .Project(stage) .Sample(1); var result = movieCollection.Aggregate(pipeline).FirstOrDefault();
Observação
Nenhum construtor para exclusão condicional
O exemplo anterior usa BsonDocument
objetos porque o driver .NET/C# não fornece um construtor para excluir campos condicionalmente. Outros drivers de linguagem MongoDB podem suportar esse recurso.Consulte a documentação do driver MongoDB para obter mais informações.
Se o documento de amostra contiver o campo imdb.votes
, o pipeline retornará um documento semelhante ao seguinte:
{ "_id" : { "$oid" : "573a1390f29313caabcd42e8" }, "title" : "The Great Train Robbery" "imdb" : { "rating" : 7.4000000000000004, "id" : 439, "votes" : 9847 } }
Se o documento não contiver o campo imdb.votes
, o pipeline retornará um documento semelhante ao seguinte:
{ "_id" : { "$oid" : "573a1398f29313caabce94a3" }, "title" : "This Is Spinal Tap", "imdb" : { "rating" : 8.0, "id" : 88258 } }
Incluir campos calculados
Para incluir campos calculados nos documentos de resultado ao usar o driver .NET/C#, chame o método Expression()
no construtor de projeção e passe uma expressão que inclua os campos calculados. Para maior segurança de tipo, você pode definir uma classe de modelo para os documentos de resultado, como a seguinte classe ProjectedMovie
:
public class ProjectedMovie { public ObjectId Id { get; set; } public string Title { get; set; } public string LeadActor { get; set; } public List<string> Crew { get; set; } }
O seguinte exemplo de código produz um documento que inclui vários campos calculados:
var pipeline = new EmptyPipelineDefinition<Movie>() .Project( Builders<Movie> .Projection .Expression(m => new ProjectedMovie { Id = m.Id, Title = m.Title, LeadActor = m.Cast[0], }) ); var result = movieCollection.Aggregate(pipeline).FirstOrDefault();
O pipeline resulta no seguinte documento:
{ "_id" : { "$oid" : "573a1390f29313caabcd42e8" }, "title" : "The Great Train Robbery" "leadActor" : "A.C. Abadie", ... }
Projetar novos campos de array
Para projeto novos campos de array nos documentos de resultado ao usar o driver .NET/C#, chame o método Expression()
no construtor de projeção e passe uma expressão que inclua os novos campos de array. Para maior segurança de tipo, você pode definir uma classe de modelo para os documentos de resultado, como a seguinte classe ProjectedMovie
:
public class ProjectedMovie { public ObjectId Id { get; set; } public string Title { get; set; } public string LeadActor { get; set; } public List<string> Crew { get; set; } }
O exemplo de código a seguir produz documentos que incluem um novo campo de array , crew
, que contém valores dos campos directors
e writers
:
var pipeline = new EmptyPipelineDefinition<Movie> () .Project( Builders<Movie> .Projection .Expression(m => new ProjectedMovie { Id = m.Id, Title = m.Title, LeadActor = m.Cast[0], Crew = m.Directors.Concat(m.Writers).ToList() } ) ) .Sample(1); var result = movieCollection.Aggregate(pipeline).FirstOrDefault();
O pipeline retorna um documento semelhante ao seguinte:
{ "_id" : { "$oid" : "573a1395f29313caabce2297" }, "title" : "The Chalk Garden", "leadActor" : "Deborah Kerr", "crew" : ["Ronald Neame", "John Michael Hayes (screenplay)", "Enid Bagnold (from the play by)"] }
Se a especificação da array incluir campos que inexistentes em um documento, o pipeline substituirá null
como valor desse campo. Por exemplo, o seguinte exemplo de código projeta os campos directors
, writers
e um campo inexistente , makeupArtists
como elementos em um novo campo denominado crew
:
var stage = new BsonDocument { { "crew", new BsonArray { "$directors", "$writers", "$makeupArtists" } } }; var pipeline = new EmptyPipelineDefinition<Movie>() .Project(stage) .Sample(1); var result = movieCollection.Aggregate(pipeline).FirstOrDefault();
O pipeline retorna um documento semelhante ao seguinte:
{ "_id" : { "$oid" : "573a1399f29313caabced0d9" }, "crew" : [["Bill Kroyer"], ["Jim Cox (screenplay)", "Diana Young (original stories)"], null] }
Observação
A classe de construtores evita campos ausentes
O exemplo anterior usa BsonDocument
objetos porque o driver .NET/C# gera um erro de tempo de compilação se você tentar usar construtores para adicionar um campo ausente a uma array. Outros drivers de linguagem MongoDB podem suportar esse recurso.Consulte a documentação do driver MongoDB para obter mais informações.