In this guide, you can learn how to use aggregation operations in the Kotlin driver.
Aggregation operations process data in your MongoDB collections and return computed results. MongoDB's aggregation pipeline, which is part of the Query API, is modeled on the concept of data-processing pipelines. Documents enter a multi-stage pipeline that transforms the documents into an aggregated result.
Tip Complete Aggregation TutorialsYou can find tutorials that provide detailed explanations of common aggregation tasks in the Complete Aggregation Pipeline Tutorials section of the Server manual. Select a tutorial, and then pick Kotlin (Coroutine) from the Select your language drop-down menu in the upper-right corner of the page.
The functionality of an aggregation is similar to what occurs in a car factory. Within the car factory is an assembly line, along which are assembly stations with specialized tools to do a specific job, like drills and welders. Raw parts enter the factory, and the factory transforms them and assembles them into a finished product.
The aggregation pipeline is the assembly line, aggregation stages are the assembly stations, and operator expressions are the specialized tools.
Using find
operations, you can:
select what documents to return
select what fields to return
sort the results
Using aggregation
operations, you can:
perform all find
operations
rename fields
calculate fields
summarize data
group values
Aggregation operations have some limitations you must keep in mind:
Returned documents must not violate the BSON document size limit of 16 megabytes.
Pipeline stages have a memory limit of 100 megabytes by default. If required, you may exceed this limit by using the allowDiskUse method.
Important $graphLookup exceptionThe $graphLookup stage has a strict memory limit of 100 megabytes and will ignore allowDiskUse
.
The examples use a collection of the following data in MongoDB:
[ {"name": "Sun Bakery Trattoria", "contact": {"phone": "386-555-0189", "email": "SunBakeryTrattoria@example.org", "location": [-74.0056649, 40.7452371]}, "stars": 4, "categories": ["Pizza", "Pasta", "Italian", "Coffee", "Sandwiches"]}, {"name": "Blue Bagels Grill", "contact": {"phone": "786-555-0102", "email": "BlueBagelsGrill@example.com", "location": [-73.92506, 40.8275556]}, "stars": 3, "categories": ["Bagels", "Cookies", "Sandwiches"]}, {"name": "XYZ Bagels Restaurant", "contact": {"phone": "435-555-0190", "email": "XYZBagelsRestaurant@example.net", "location": [-74.0707363, 40.59321569999999]}, "stars": 4, "categories": ["Bagels", "Sandwiches", "Coffee"]}, {"name": "Hot Bakery Cafe", "contact": {"phone": "264-555-0171", "email": "HotBakeryCafe@example.net", "location": [-73.96485799999999, 40.761899]}, "stars": 4, "categories": ["Bakery", "Cafe", "Coffee", "Dessert"]}, {"name": "Green Feast Pizzeria", "contact": {"phone": "840-555-0102", "email": "GreenFeastPizzeria@example.com", "location": [-74.1220973, 40.6129407]}, "stars": 2, "categories": ["Pizza", "Italian"]}, {"name": "ZZZ Pasta Buffet", "contact": {"phone": "769-555-0152", "email": "ZZZPastaBuffet@example.com", "location": [-73.9446421, 40.7253944]}, "stars": 0, "categories": ["Pasta", "Italian", "Buffet", "Cafeteria"]}, {"name": "XYZ Coffee Bar", "contact": {"phone": "644-555-0193", "email": "XYZCoffeeBar@example.net", "location": [-74.0166091, 40.6284767]}, "stars": 5, "categories": ["Coffee", "Cafe", "Bakery", "Chocolates"]}, {"name": "456 Steak Restaurant", "contact": {"phone": "990-555-0165", "email": "456SteakRestaurant@example.com", "location": [-73.9365108, 40.8497077]}, "stars": 0, "categories": ["Steak", "Seafood"]}, {"name": "456 Cookies Shop", "contact": {"phone": "604-555-0149", "email": "456CookiesShop@example.org", "location": [-73.8850023, 40.7494272]}, "stars": 4, "categories": ["Bakery", "Cookies", "Cake", "Coffee"]}, {"name": "XYZ Steak Buffet", "contact": {"phone": "229-555-0197", "email": "XYZSteakBuffet@example.org", "location": [-73.9799932, 40.7660886]}, "stars": 3, "categories": ["Steak", "Salad", "Chinese"]}]
The data in the collection is modeled by the following Restaurant
data class:
data class Restaurant( val name: String, val contact: Contact, val stars: Int, val categories: List<String>) { data class Contact( val phone: String, val email: String, val location: List<Double> )}
To perform an aggregation, pass a list of aggregation stages to the MongoCollection.aggregate()
method.
The Kotlin driver provides the Aggregates helper class that contains builders for aggregation stages.
In the following example, the aggregation pipeline:
Uses a $match stage to filter for documents whose categories
array field contains the element Bakery
. The example uses Aggregates.match
to build the $match
stage.
Uses a $group stage to group the matching documents by the stars
field, accumulating a count of documents for each distinct value of stars
.
data class Results(@BsonId val id: Int, val count: Int)val resultsFlow = collection.aggregate<Results>( listOf( Aggregates.match(Filters.eq(Restaurant::categories.name, "Bakery")), Aggregates.group( "\$${Restaurant::stars.name}", Accumulators.sum("count", 1) ) ))resultsFlow.collect { println(it) }
Results(id=4, count=2)Results(id=5, count=1)
For more information about the methods and classes mentioned in this section, see the following API Documentation:
To view information about how MongoDB executes your operation, use the explain()
method of the AggregateFlow
class. The explain()
method returns execution plans and performance statistics. An execution plan is a potential way MongoDB can complete an operation. The explain()
method provides both the winning plan (the plan MongoDB executed) and rejected plans.
You can specify the level of detail of your explanation by passing a verbosity level to the explain()
method.
The following table shows all verbosity levels for explanations and their intended use cases:
Verbosity Level
Use Case
ALL_PLANS_EXECUTIONS
You want to know which plan MongoDB will choose to run your query.
EXECUTION_STATS
You want to know if your query is performing well.
QUERY_PLANNER
You have a problem with your query and you want as much information as possible to diagnose the issue.
In the following example, we print the JSON representation of the winning plans for aggregation stages that produce execution plans:
data class Results(val name: String, val count: Int)val explanation = collection.aggregate<Results>( listOf( Aggregates.match(Filters.eq(Restaurant::categories.name, "bakery")), Aggregates.group("\$${Restaurant::stars.name}", Accumulators.sum("count", 1)) )).explain(ExplainVerbosity.EXECUTION_STATS)println(explanation.toJson(JsonWriterSettings.builder().indent(true).build()))
{ "explainVersion": "2", "queryPlanner": { }, "command": { }, }
For more information about the topics mentioned in this section, see the following resources:
Explain Output Server Manual Entry
Query Plans Server Manual Entry
ExplainVerbosity API Documentation
explain() API Documentation
AggregateFlow API Documentation
The Kotlin driver provides builders for accumulator expressions for use with $group
. You must declare all other expressions in JSON format or compatible document format.
The syntax in either of the following examples will define an $arrayElemAt expression.
The $
in front of "categories" tells MongoDB that this is a field path, using the "categories" field from the input document.
Document("\$arrayElemAt", listOf("\$categories", 0)) Document.parse("{ \$arrayElemAt: ['\$categories', 0] }")
In the following example, the aggregation pipeline uses a $project
stage and various Projections
to return the name
field and the calculated field firstCategory
whose value is the first element in the categories
field.
data class Results(val name: String, val firstCategory: String)val resultsFlow = collection.aggregate<Results>( listOf( Aggregates.project( Projections.fields( Projections.excludeId(), Projections.include("name"), Projections.computed( "firstCategory", Document("\$arrayElemAt", listOf("\$categories", 0)) ) ) ) ))resultsFlow.collect { println(it) }
Results(name=Sun Bakery Trattoria, firstCategory=Pizza)Results(name=Blue Bagels Grill, firstCategory=Bagels)Results(name=XYZ Bagels Restaurant, firstCategory=Bagels)Results(name=Hot Bakery Cafe, firstCategory=Bakery)Results(name=Green Feast Pizzeria, firstCategory=Pizza)Results(name=ZZZ Pasta Buffet, firstCategory=Pasta)Results(name=XYZ Coffee Bar, firstCategory=Coffee)Results(name=456 Steak Restaurant, firstCategory=Steak)Results(name=456 Cookies Shop, firstCategory=Bakery)Results(name=XYZ Steak Buffet, firstCategory=Steak)
For more information about the methods and classes mentioned in this section, see the following API Documentation:
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4