Docs Menu
Docs Home
/ / /
Kotlin Coroutine

Specify Which Fields to Return

On this page

  • Overview
  • Behavior
  • Explanation

In this guide, you can learn how to control which fields appear in documents returned from read operations with the MongoDB Kotlin driver.

Many read requests require only a subset of fields in a document. For example, when logging a user in you may only need their username, and not all of their profile information. By default, queries in MongoDB return all fields in matching documents. You can use a projection to return only the data you need.

A projection is a document that instructs MongoDB which fields of a document to return. Use the Projections class to construct a projection document.

Projections work in two ways:

  • Explicitly including fields. This has the side-effect of implicitly excluding all unspecified fields.

  • Implicitly excluding fields. This has the side-effect of implicitly including all unspecified fields.

These two methods of projection are mutually exclusive: if you explicitly include fields, you cannot explicitly exclude fields, and vice versa.

Important

The _id field is not subject to these mechanics. You must explicitly exclude the _id field if you do not want it returned. You can exclude the _id field even if you have specified certain fields to include.

Consider the following collection containing documents that describe varieties of fruit:

{ "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
{ "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
{ "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
{ "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },

This data is modeled using the following Kotlin data class:

data class Fruit(
@BsonId val id: Int,
val name: String,
val qty: Int,
val rating: Int
)

In the following query, pass the projection to return the name field of each document. The results are modeled using the FruitName Kotlin data class:

data class FruitName(
@BsonId val id: Int? = null,
val name: String
)
// Return all documents with only the name field
val filter = Filters.empty()
val projection = Projections.fields(
Projections.include(FruitName::name.name)
)
val flowResults = collection.find<FruitName>(filter).projection(projection)
flowResults.collect { println(it)}
FruitName(id=1, name=apples),
FruitName(id=2, name=bananas),
FruitName(id=3, name=oranges),
FruitName(id=4, name=avocados)

The projection document specifies that the read operation result should include the name field of each returned document. As a result, this projection implicitly excludes the qty and rating fields. Chaining this projection to find() with an empty query filter yields the above results.

Despite the fact that this projection only explicitly included the name field, the query also returned the _id field, represented by id in the data class.

The _id field is a special case: it is always included in every query result unless explicitly excluded. That's because the _id field is a unique identifier for each document, a property that can be useful when constructing queries.

The _id is the only exception to the mutually exclusive include-exclude behavior in projections: you can explicitly exclude the _id field even when explicitly including other fields if you do not want _id to be present in returned documents.

data class FruitName(
@BsonId val id: Int? = null,
val name: String
)
// Return all documents with *only* the name field
// excludes the id
val filter = Filters.empty()
val projection = Projections.fields(
Projections.include(FruitName::name.name),
Projections.excludeId()
)
val flowResults = collection.find<FruitName>(filter).projection(projection)
flowResults.collect { println(it)}
FruitName(name=apples),
FruitName(name=bananas),
FruitName(name=oranges),
FruitName(name=avocados)

The projection document specifies that the read operation result should include the name field of each returned document, and specifies to exclude the _id field. As a result, this projection implicitly excludes the qty and rating fields. Chaining this projection to find() with an empty query filter yields the above results.

You can also specify multiple fields to include in your projection.

Tip

The order in which you specify the fields in the projection does not alter the order in which they are returned.

This example that identifies two fields to include in the projection yields the following results using the FruitRating Kotlin data class:

data class FruitRating(
val name: String,
val rating: Int
)
val filter = Filters.empty()
val projection = Projections.fields(
Projections.include(FruitRating::name.name, FruitRating::rating.name),
Projections.excludeId()
)
val flowResults = collection.find<FruitRating>(filter).projection(projection)
flowResults.collect { println(it)}
FruitRating(name=apples, rating=3),
FruitRating(name=bananas, rating=1),
FruitRating(name=oranges, rating=2),
FruitRating(name=avocados, rating=5)

For additional projection examples, see the MongoDB Manual page on Project Fields to Return from Query.

Next

MongoDB Kotlin Driver