Docs Menu
Docs Home
/ / /
Kotlin Coroutine
/ /

Projections Builders

On this page

  • Overview
  • Sample Documents and Examples
  • Projection Operations
  • Inclusion
  • Exclusion
  • Combining Projections
  • Exclusion of _id
  • Project an Array Element Match
  • Project an Array Slice
  • Project a Text Score

In this guide, you can learn how to specify projections using builders in the MongoDB Kotlin driver.

MongoDB supports field projection, specifying which fields to include and exclude when returning results from a query. Projection in MongoDB follows some basic rules:

  • The _id field is always included unless explicitly excluded

  • Specifying a field for inclusion implicitly excludes all other fields except the _id field

  • Specifying a field for exclusion removes only that field in a query result

Find more information about projection mechanics in the Project Fields to Return from Query guide in the MongoDB Server documentation.

The Projections class provides static factory methods for all the MongoDB projection operators. Each method returns an instance of the BSON type which you can pass to any method that expects a projection.

Tip

For brevity, you may choose to import the methods of the Projections class:

import com.mongodb.client.model.Projections.*

The following sections feature examples that run query and projection operations on a sample collection called projection_builders. Each section uses a variable named collection to refer to the MongoCollection instance of the projection_builders collection.

The collection contains the following documents, representing the monthly average temperatures in Celsius for the years 2018 and 2019:

{
"year" : 2018,
"type" : "even number but not a leap year",
"temperatures" : [
{ "month" : "January", "avg" : 9.765 },
{ "month" : "February", "avg" : 9.675 },
{ "month" : "March", "avg" : 10.004 },
{ "month" : "April", "avg" : 9.983 },
{ "month" : "May", "avg" : 9.747 },
{ "month" : "June", "avg" : 9.65 },
{ "month" : "July", "avg" : 9.786 },
{ "month" : "August", "avg" : 9.617 },
{ "month" : "September", "avg" : 9.51 },
{ "month" : "October", "avg" : 10.042 },
{ "month" : "November", "avg" : 9.452 },
{ "month" : "December", "avg" : 9.86 }
]
},
{
"year" : 2019,
"type" : "odd number, can't be a leap year",
"temperatures" : [
{ "month" : "January", "avg" : 10.023 },
{ "month" : "February", "avg" : 9.808 },
{ "month" : "March", "avg" : 10.43 },
{ "month" : "April", "avg" : 10.175 },
{ "month" : "May", "avg" : 9.648 },
{ "month" : "June", "avg" : 9.686 },
{ "month" : "July", "avg" : 9.794 },
{ "month" : "August", "avg" : 9.741 },
{ "month" : "September", "avg" : 9.84 },
{ "month" : "October", "avg" : 10.15 },
{ "month" : "November", "avg" : 9.84 },
{ "month" : "December", "avg" : 10.366 }
]
}

The following data class is used to represent the documents in the collection:

data class YearlyTemperature(
@BsonId val id: ObjectId,
val year: Int,
val type: String,
val temperatures: List<MonthlyTemperature>
) {
data class MonthlyTemperature(
val month: String,
val avg: Double
)
}

The following sections contain information on the available projection operations and how to construct them using the Projections class.

Use the include() method to specify the inclusion of one or more fields.

The following example includes the year field and implicitly the _id field:

data class Results(@BsonId val id: ObjectId, val year: Int)
val filter = Filters.empty()
val projection = Projections.include(YearlyTemperature::year.name)
val resultsFlow = collection.find<Results>(filter).projection(projection)
resultsFlow.collect { println(it) }
Results(id=6467808db5003e6354a1ee22, year=2018)
Results(id=6467808db5003e6354a1ee23, year=2019)

The following example includes the year and type fields and implicitly the _id field:

data class Results(@BsonId val id: ObjectId, val year: Int, val type: String)
val filter = Filters.empty()
val projection = Projections.include(YearlyTemperature::year.name, YearlyTemperature::type.name)
val resultsFlow = collection.find<Results>(filter).projection(projection)
resultsFlow.collect { println(it) }
Results(id=646780e3311323724f69a907, year=2018, type=even number but not a leap year)
Results(id=646780e3311323724f69a908, year=2019, type=odd number, can't be a leap year)

Use the exclude() method to specify the exclusion of one or more fields.

The following example excludes the temperatures field:

data class Results(@BsonId val id: ObjectId, val year: Int, val type: String)
val filter = Filters.empty()
val projection = Projections.exclude(YearlyTemperature::temperatures.name)
val resultsFlow = collection.find<Results>(filter).projection(projection)
resultsFlow.collect { println(it) }
Results(id=6462976102c85b29a7bfc9d5, year=2018, type=even number but not a leap year)
Results(id=6462976102c85b29a7bfc9d6, year=2019, type=odd number, can't be a leap year)

The following example excludes the temperatures and type fields:

data class Results(@BsonId val id: ObjectId, val year: Int)
val filter = Filters.empty()
val projection = Projections.exclude(YearlyTemperature::temperatures.name, YearlyTemperature::type.name)
val resultsFlow = collection.find<Results>(filter).projection(projection)
resultsFlow.collect { println(it) }
Results(id=64629783d7760d2365215147, year=2018)
Results(id=64629783d7760d2365215148, year=2019)

Use the fields() method to combine multiple projections.

The following example includes the year and type fields and excludes the _id field:

data class Results(val year: Int, val type: String)
val filter = Filters.empty()
val projection = Projections.fields(
Projections.include(YearlyTemperature::year.name, YearlyTemperature::type.name),
Projections.excludeId()
)
val resultsFlow = collection.find<Results>(filter).projection(projection)
resultsFlow.collect { println(it) }
Results(year=2018, type=even number but not a leap year)
Results(year=2019, type=odd number, can't be a leap year)

Use the excludeId() convenience method to specify the exclusion of the _id field:

data class Results(val year: Int, val type: String, val temperatures: List<YearlyTemperature.MonthlyTemperature>)
val filter = Filters.empty()
val projection = Projections.excludeId()
val resultsFlow = collection.find<Results>(filter).projection(projection)
resultsFlow.collect { println(it) }
Results(year=2018, type=even number but not a leap year, temperatures=[MonthlyTemperature(month=January, avg=9.765), MonthlyTemperature(month=February, avg=9.675), MonthlyTemperature(month=March, avg=10.004), MonthlyTemperature(month=April, avg=9.983), MonthlyTemperature(month=May, avg=9.747), MonthlyTemperature(month=June, avg=9.65), MonthlyTemperature(month=July, avg=9.786), MonthlyTemperature(month=August, avg=9.617), MonthlyTemperature(month=September, avg=9.51), MonthlyTemperature(month=October, avg=10.042), MonthlyTemperature(month=November, avg=9.452), MonthlyTemperature(month=December, avg=9.86)])
Results(year=2019, type=odd number, can't be a leap year, temperatures=[MonthlyTemperature(month=January, avg=10.023), MonthlyTemperature(month=February, avg=9.808), MonthlyTemperature(month=March, avg=10.43), MonthlyTemperature(month=April, avg=10.175), MonthlyTemperature(month=May, avg=9.648), MonthlyTemperature(month=June, avg=9.686), MonthlyTemperature(month=July, avg=9.794), MonthlyTemperature(month=August, avg=9.741), MonthlyTemperature(month=September, avg=9.84), MonthlyTemperature(month=October, avg=10.15), MonthlyTemperature(month=November, avg=9.84), MonthlyTemperature(month=December, avg=10.366)])

Use the elemMatch(String, Bson) method variant to specify an array projection that will include the first element of an array that matches a supplied query filter. This filtering occurs after all documents matching the query filter (if supplied) are retrieved.

Note

Only the first element that matches the specified query filter will be included, regardless of how many matches there may be.

The following example projects the first element of the temperatures array where the avg field is greater that 10.1:

data class Results(
val year: Int,
val temperatures: List<YearlyTemperature.MonthlyTemperature>?
)
val filter = Filters.empty()
val projection = Projections.fields(
Projections.include(YearlyTemperature::year.name),
Projections.elemMatch(
YearlyTemperature::temperatures.name,
Filters.gt(YearlyTemperature.MonthlyTemperature::avg.name, 10.1)
)
)
val resultsFlow = collection.find<Results>(filter).projection(projection)
resultsFlow.collect { println(it) }
Results(year=2018, temperatures=null)
Results(year=2019, temperatures=[MonthlyTemperature(month=March, avg=10.43)])

When you've specified matching criteria in the query portion of your operation, use the elemMatch(String) method variant to specify a positional projection to include the first element of an array. Only documents that match the query filter will be retrieved.

Important

In MongoDB version 4.4 and earlier, the specified array field must appear in the query filter. Beginning in MongoDB 4.4, you can use a positional project on an array field that does not appear in the query filter.

The following example projects the first element of the temperatures array:

data class Results(
val year: Int,
val temperatures: List<YearlyTemperature.MonthlyTemperature>
)
val filter = Filters.gt(
"${YearlyTemperature::temperatures.name}.${YearlyTemperature.MonthlyTemperature::avg.name}",
10.1
)
val projection = Projections.fields(
Projections.include(YearlyTemperature::year.name),
Projections.elemMatch(YearlyTemperature::temperatures.name)
)
val resultsFlow = collection.find<Results>(filter).projection(projection)
resultsFlow.collect { println(it) }
Results(year=2019, temperatures=[MonthlyTemperature(month=March, avg=10.43)])

Use the slice() method to project a slice of an array.

The following example projects the first 6 elements of the temperatures array:

data class Results(val temperatures: List<YearlyTemperature.MonthlyTemperature>)
val filter = Filters.empty()
// First half of the year
val projection = Projections.fields(
Projections.slice(YearlyTemperature::temperatures.name, 6),
Projections.excludeId()
)
val resultsFlow = collection.find<Results>(filter)
.projection(projection)
resultsFlow.collect { println(it) }
Results(temperatures=[MonthlyTemperature(month=January, avg=9.765), MonthlyTemperature(month=February, avg=9.675), MonthlyTemperature(month=March, avg=10.004), MonthlyTemperature(month=April, avg=9.983), MonthlyTemperature(month=May, avg=9.747), MonthlyTemperature(month=June, avg=9.65)])
Results(temperatures=[MonthlyTemperature(month=January, avg=10.023), MonthlyTemperature(month=February, avg=9.808), MonthlyTemperature(month=March, avg=10.43), MonthlyTemperature(month=April, avg=10.175), MonthlyTemperature(month=May, avg=9.648), MonthlyTemperature(month=June, avg=9.686)])

The following example skips the first 6 elements of the temperatures array and projects the next 6:

data class Results(val temperatures: List<YearlyTemperature.MonthlyTemperature>)
val filter = Filters.empty()
// Second half of the year
val projection = Projections.fields(
Projections.slice(YearlyTemperature::temperatures.name, 6, 6),
Projections.excludeId()
)
val resultsFlow = collection.find<Results>(filter)
.projection(projection)
resultsFlow.collect { println(it) }
Results(temperatures=[MonthlyTemperature(month=July, avg=9.786), MonthlyTemperature(month=August, avg=9.617), MonthlyTemperature(month=September, avg=9.51), MonthlyTemperature(month=October, avg=10.042), MonthlyTemperature(month=November, avg=9.452), MonthlyTemperature(month=December, avg=9.86)])
Results(temperatures=[MonthlyTemperature(month=July, avg=9.794), MonthlyTemperature(month=August, avg=9.741), MonthlyTemperature(month=September, avg=9.84), MonthlyTemperature(month=October, avg=10.15), MonthlyTemperature(month=November, avg=9.84), MonthlyTemperature(month=December, avg=10.366)])

Use the metaTextScore() method to specify a projection of the score of a text query.

The following example projects the text score as the value of the score field:

data class Results(val year: Int, val score: Double)
val filter = Filters.text("even number")
val projection = Projections.fields(
Projections.include(YearlyTemperature::year.name),
Projections.metaTextScore("score")
)
val resultsFlow = collection.find<Results>(filter).projection(projection)
resultsFlow.collect { println(it) }
Results(year=2018, score=1.25)
Results(year=2019, score=0.625)

Back

Indexes