> Portal Navigation: > > - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version. > - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages). > - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`). > - Top-level index of all portals: https://dev.wix.com/docs/llms.txt > - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt # Method name: data.items.aggregatePipeline(dataCollectionId: string, pipeline: AggregationPipeline, options: WixDataAggregateOptions) # Method Link: https://dev.wix.com/docs/sdk/business-solutions/data/items/aggregate-pipeline.md # Method Description: Runs an aggregation pipeline on a data collection and returns the results. Aggregations enable you to perform advanced data calculations, transformations, and groupings. While [`aggregate()`](https://dev.wix.com/docs/sdk/backend-modules/data/items/aggregate.md) allows you to perform basic aggregations, `aggregatePipeline()` allows you to perform advanced aggregations sequentially in stages, with each stage transforming the results of the previous stage. When calling the `aggregatePipeline()` method, specify the collection ID and an aggregation pipeline. To build the pipeline, call the [`pipelineBuilder()`](https://dev.wix.com/docs/sdk/backend-modules/data/items/pipeline-builder.md) method and chain [`PipelineBuilder`](https://dev.wix.com/docs/sdk/backend-modules/data/items/pipeline-builder/introduction.md) methods to add stages and configure paging. `aggregatePipeline()` returns the aggregated results and pagination information. > **Note**: You can only build an aggregation pipeline for collections [created in the CMS](https://support.wix.com/en/article/cms-formerly-content-manager-creating-a-collection) or with the [Data Collections API](https://dev.wix.com/docs/sdk/backend-modules/data/collections/introduction.md). They cannot be used on [Wix app collections](https://support.wix.com/en/article/cms-formerly-content-manager-working-with-wix-app-collections) or [external collections](https://dev.wix.com/docs/develop-websites/articles/databases/external-databases/overview/integrating-external-databases-with-your-wix-site.md). # Method Permissions: - Read Data Items # Method Permissions Scopes IDs: - SCOPE.DC-DATA.READ # Method Code Examples: ## Basic aggregatePipeline() usage with simple stages ```javascript import { items } from "@wix/data"; const { stages, pipelineBuilder } = items; // Create a simple pipeline with filter and sort stages const pipeline = [ stages.filter().eq("year", 2010), stages.sort().descending("population") ]; const builder = pipelineBuilder() .withStages(pipeline); const response = await items.aggregatePipeline("PopulationData", builder.build()); if (response.results && response.results.length > 0) { const items = response.results; const firstItem = items[0]; const numItems = response.results.length; } else { // handle case where no matching items found } /* Expected response format: * { * results: [ * { * "_id": "nyc-2010", * "city": "New York", * "state": "NY", * "year": 2010, * "population": 8192000 * }, * { * "_id": "la-2010", * "city": "Los Angeles", * "state": "CA", * "year": 2010, * "population": 3796000 * } * ], * pagingMetadata: { * count: 2, * offset: 0, * total: 10, * cursors: { * next: "next_cursor_token", * prev: null * } * } * } */ ``` ## Advanced aggregatePipeline() with complex multi-stage pipeline ```javascript import { items } from "@wix/data"; const { stages, expressions, pipelineBuilder } = items; // Create a complex multi-stage pipeline with filtering, grouping, and projection const pipeline = [ // Stage 1: Filter data for specific years stages.filter() .ge("year", 2010) .le("year", 2020), // Stage 2: Group by state and calculate aggregations stages.group() .by(expressions.field("state"), "state") .sum(expressions.field("population"), "totalPopulation") .avg(expressions.field("population"), "avgPopulation") .count("cityCount") .max(expressions.field("population"), "largestCity") .min(expressions.field("population"), "smallestCity"), // Stage 3: Filter groups with significant population stages.filter().gt("totalPopulation", 5000000), // Stage 4: Project specific fields and add computed fields stages.project() .include("state", "totalPopulation", "cityCount") .reshape("avgPopulationRounded", expressions.floor(expressions.field("avgPopulation"))) .reshape("populationDensityCategory", expressions.text("High Density") ), // Stage 5: Sort by total population descending stages.sort().descending("totalPopulation") ]; const builder = pipelineBuilder() .withStages(pipeline); const response = await items.aggregatePipeline("PopulationData", builder.build()); /* Expected response format: * { * results: [ * { * "state": "CA", * "totalPopulation": 15234000, * "cityCount": 4, * "avgPopulationRounded": 3809000, * "populationDensityCategory": "High Density" * }, * { * "state": "NY", * "totalPopulation": 12456000, * "cityCount": 3, * "avgPopulationRounded": 4152000, * "populationDensityCategory": "High Density" * } * ], * pagingMetadata: { * count: 2, * offset: 0, * total: 5, * cursors: { * next: "next_cursor_token", * prev: null * } * } * } */ ``` ## Real-world aggregatePipeline() example with pagination and options ```javascript import { items } from "@wix/data"; const { stages, expressions, pipelineBuilder } = items; // Real-world pipeline with pagination for large datasets const pipeline = [ // Stage 1: Filter for recent data stages.filter().ge("year", 2015), // Stage 2: Group by state and year for trend analysis stages.group() .by( expressions.field("state"), "state", expressions.field("year"), "year" ) .sum(expressions.field("population"), "yearlyPopulation") .count("citiesReported"), // Stage 3: Sort by state and year for consistent pagination stages.sort() .ascending("state") .ascending("year"), ]; // Execute with additional options and pagination const builder = pipelineBuilder() .withStages(pipeline) .withPaging({ limit: 10, offset: 0 }); const options = { returnTotalCount: true, suppressAuth: false }; const response = await items.aggregatePipeline("PopulationData", builder.build(), options); /* Expected response format: * { * results: [ * { * "state": "AL", * "year": 2015, * "yearlyPopulation": 1234567, * "citiesReported": 3 * }, * { * "state": "AL", * "year": 2016, * "yearlyPopulation": 1245678, * "citiesReported": 3 * } * // ... 8 more items * ], * pagingMetadata: { * count: 10, * offset: 0, * total: 150, * cursors: { * next: "next_cursor_token", * prev: null * } * } * } */ ``` ## String processing pipeline demonstrating text manipulation expressions ```javascript import { items } from "@wix/data"; const { stages, expressions, pipelineBuilder } = items; // String processing pipeline demonstrating text manipulation expressions const pipeline = [ // Stage 1: Filter for non-empty city names stages.filter().ne("cityName", ""), // Stage 2: Project with string transformations stages.project() .include("_id", "cityName", "state", "population") // Create standardized city name (Title Case) .reshape("cityNameStandardized", expressions.concat( expressions.toUpper(expressions.substring(expressions.field("cityName"), expressions.numeric(0), expressions.numeric(1))), expressions.toLower(expressions.substring(expressions.field("cityName"), expressions.numeric(1))) ) ) // Create state abbreviation (first 2 characters uppercase) .reshape("stateAbbr", expressions.toUpper(expressions.substring(expressions.field("state"), expressions.numeric(0), expressions.numeric(2))) ) // Create full location string .reshape("fullLocation", expressions.concat( expressions.field("cityNameStandardized"), expressions.text(", "), expressions.field("stateAbbr") ) ) // Calculate name length for analysis .reshape("cityNameLength", expressions.length(expressions.field("cityName"))) // Convert population to string for display .reshape("populationDisplay", expressions.concat( expressions.stringify(expressions.field("population")), expressions.text(" residents") ) ), // Stage 3: Filter cities with reasonable name lengths stages.filter() .ge("cityNameLength", 3) .le("cityNameLength", 20), // Stage 4: Sort by standardized city name stages.sort().ascending("cityNameStandardized") ]; const builder = pipelineBuilder() .withStages(pipeline); const response = await items.aggregatePipeline("CityData", builder.build()); /* Expected response format: * { * results: [ * { * "_id": "nyc-001", * "cityName": "new york", * "state": "New York", * "population": 8192000, * "cityNameStandardized": "New york", * "stateAbbr": "NE", * "fullLocation": "New york, NE", * "cityNameLength": 8, * "populationDisplay": "8192000 residents" * }, * { * "_id": "sf-001", * "cityName": "SAN FRANCISCO", * "state": "California", * "population": 873965, * "cityNameStandardized": "San francisco", * "stateAbbr": "CA", * "fullLocation": "San francisco, CA", * "cityNameLength": 13, * "populationDisplay": "873965 residents" * } * ], * pagingMetadata: { * count: 2, * offset: 0, * total: 15, * cursors: { * next: "next_cursor_token", * prev: null * } * } * } */ ``` ## Array unwinding and object transformation pipeline ```javascript import { createClient } from "@wix/sdk"; import { items } from "@wix/data"; const { stages, expressions, pipelineBuilder } = items; // Import the auth strategy for the relevant access type // Import the relevant host module if needed const wixClient = createClient({ modules: { items }, // Include the auth strategy and host as relevant }); // Array unwinding and object transformation pipeline const pipeline = [ // Stage 1: Filter cities with neighborhoods data stages.filter().exists("neighborhoods"), // Stage 2: Unwind neighborhoods array - creates one document per neighborhood stages.unwind("neighborhoods"), // Stage 3: Project and reshape neighborhood data stages.project() .include("cityName", "state", "population") .include("neighborhoods") // This will be the individual neighborhood after unwind .reshape("neighborhoodName", expressions.field("neighborhoods.name")) .reshape("neighborhoodPopulation", expressions.field("neighborhoods.population")) .reshape("neighborhoodType", expressions.field("neighborhoods.type")), // Stage 4: Convert demographics object to array for analysis stages.objectToArray("neighborhoods.demographics", "demographicPairs"), // Stage 5: Unwind demographic pairs to analyze each demographic separately stages.unwind("demographicPairs"), // Stage 6: Project final structure with demographic analysis stages.project() .include("cityName", "state", "neighborhoodName", "neighborhoodPopulation") .reshape("demographicKey", expressions.field("demographicPairs.k")) .reshape("demographicValue", expressions.field("demographicPairs.v")) .reshape("locationSummary", expressions.concat( expressions.field("neighborhoodName"), expressions.text(" in "), expressions.field("cityName"), expressions.text(", "), expressions.field("state") ) ), // Stage 7: Filter for significant demographic values stages.filter().gt("demographicValue", 1000), // Stage 8: Sort by city, then neighborhood, then demographic key stages.sort() .ascending("cityName") .ascending("neighborhoodName") .ascending("demographicKey") ]; const builder = pipelineBuilder() .withStages(pipeline); const response = await wixClient.items.aggregatePipeline("CityNeighborhoods", builder.build()); /* Sample input data structure: * { * "_id": "nyc-001", * "cityName": "New York", * "state": "NY", * "population": 8192000, * "neighborhoods": [ * { * "name": "Manhattan", * "population": 1630000, * "type": "Borough", * "demographics": { * "under18": 245000, * "age18to65": 1140000, * "over65": 245000 * } * }, * { * "name": "Brooklyn", * "population": 2590000, * "type": "Borough", * "demographics": { * "under18": 518000, * "age18to65": 1813000, * "over65": 259000 * } * } * ] * } */ /* Expected response format: * { * results: [ * { * "cityName": "New York", * "state": "NY", * "neighborhoodName": "Brooklyn", * "neighborhoodPopulation": 2590000, * "demographicKey": "age18to65", * "demographicValue": 1813000, * "locationSummary": "Brooklyn in New York, NY" * }, * { * "cityName": "New York", * "state": "NY", * "neighborhoodName": "Brooklyn", * "neighborhoodPopulation": 2590000, * "demographicKey": "under18", * "demographicValue": 518000, * "locationSummary": "Brooklyn in New York, NY" * }, * { * "cityName": "New York", * "state": "NY", * "neighborhoodName": "Manhattan", * "neighborhoodPopulation": 1630000, * "demographicKey": "age18to65", * "demographicValue": 1140000, * "locationSummary": "Manhattan in New York, NY" * } * ], * pagingMetadata: { * count: 3, * offset: 0, * total: 12, * cursors: { * next: "next_cursor_token", * prev: null * } * } * } */ ``` ## Complex mathematical calculations pipeline with nested expressions ```javascript import { createClient } from "@wix/sdk"; import { items } from "@wix/data"; const { stages, expressions, pipelineBuilder } = items; // Import the auth strategy for the relevant access type // Import the relevant host module if needed const wixClient = createClient({ modules: { items }, // Include the auth strategy and host as relevant }); // Complex mathematical calculations pipeline demonstrating nested expressions const pipeline = [ // Stage 1: Filter for cities with complete financial data stages.filter() .exists("population") .exists("medianIncome") .exists("housingCosts") .exists("taxRate"), // Stage 2: Project with complex mathematical transformations stages.project() .include("_id", "cityName", "state", "population", "medianIncome", "housingCosts", "taxRate") // Calculate population growth rate (assuming we have previous year data) .reshape("populationGrowthRate", expressions.abs( expressions.divide( expressions.subtract( expressions.field("population"), expressions.field("previousYearPopulation") ), expressions.field("previousYearPopulation") ) ) ) // Calculate take-home income after taxes .reshape("takeHomeIncome", expressions.multiply( expressions.field("medianIncome"), expressions.subtract( expressions.numeric(1), expressions.divide(expressions.field("taxRate"), expressions.numeric(100)) ) ) ) // Calculate housing affordability ratio .reshape("housingAffordabilityRatio", expressions.divide( expressions.field("housingCosts"), expressions.field("takeHomeIncome") ) ) // Calculate cost of living index using complex formula .reshape("costOfLivingIndex", expressions.add( expressions.multiply( expressions.field("housingCosts"), expressions.numeric(0.3) ), expressions.multiply( expressions.subtract( expressions.field("medianIncome"), expressions.field("housingCosts") ), expressions.numeric(0.7) ) ) ) // Calculate population density per square mile (rounded up) .reshape("populationDensity", expressions.ceil( expressions.divide( expressions.field("population"), expressions.field("areaSquareMiles") ) ) ) // Calculate economic score using weighted formula .reshape("economicScore", expressions.floor( expressions.add( expressions.multiply( expressions.field("takeHomeIncome"), expressions.numeric(0.4) ), expressions.multiply( expressions.subtract( expressions.numeric(100), expressions.multiply( expressions.field("housingAffordabilityRatio"), expressions.numeric(100) ) ), expressions.numeric(0.6) ) ) ) ) // Calculate year-based metrics (leap year detection) .reshape("isLeapYear", expressions.mod(expressions.field("year"), expressions.numeric(4)) ) // Calculate total municipal budget estimate .reshape("estimatedMunicipalBudget", expressions.sum( expressions.multiply( expressions.field("population"), expressions.numeric(1200) ), expressions.multiply( expressions.field("medianIncome"), expressions.field("taxRate") ), expressions.numeric(5000000) ) ), // Stage 3: Filter for economically viable cities stages.filter() .ge("economicScore", 50) .le("housingAffordabilityRatio", 0.5), // Stage 4: Group by state for regional analysis stages.group() .by(expressions.field("state"), "state") .avg(expressions.field("economicScore"), "avgEconomicScore") .sum(expressions.field("population"), "totalPopulation") .max(expressions.field("takeHomeIncome"), "highestTakeHomeIncome") .min(expressions.field("housingAffordabilityRatio"), "bestAffordabilityRatio") .count("viableCitiesCount"), // Stage 5: Calculate final state rankings stages.project() .include("state", "totalPopulation", "viableCitiesCount") .reshape("avgEconomicScoreRounded", expressions.floor(expressions.field("avgEconomicScore"))) .reshape("highestTakeHomeIncomeRounded", expressions.floor(expressions.field("highestTakeHomeIncome"))) .reshape("stateRankingScore", expressions.add( expressions.multiply( expressions.field("avgEconomicScore"), expressions.numeric(0.6) ), expressions.multiply( expressions.field("viableCitiesCount"), expressions.numeric(10) ) ) ), // Stage 6: Sort by ranking score stages.sort().descending("stateRankingScore") ]; const builder = pipelineBuilder() .withStages(pipeline); const response = await wixClient.items.aggregatePipeline("CityEconomics", builder.build()); /* Expected response format: * { * results: [ * { * "state": "Texas", * "totalPopulation": 15234567, * "viableCitiesCount": 8, * "avgEconomicScoreRounded": 72, * "highestTakeHomeIncomeRounded": 85000, * "stateRankingScore": 123.2 * }, * { * "state": "California", * "totalPopulation": 22456789, * "viableCitiesCount": 6, * "avgEconomicScoreRounded": 68, * "highestTakeHomeIncomeRounded": 95000, * "stateRankingScore": 100.8 * } * ], * pagingMetadata: { * count: 2, * offset: 0, * total: 8, * cursors: { * next: "next_cursor_token", * prev: null * } * } * } */ ``` ## Advanced filtering and projection patterns pipeline ```javascript import { createClient } from "@wix/sdk"; import { items } from "@wix/data"; const { stages, expressions, pipelineBuilder } = items; // Import the auth strategy for the relevant access type // Import the relevant host module if needed const wixClient = createClient({ modules: { items }, // Include the auth strategy and host as relevant }); // Advanced filtering and projection patterns pipeline const pipeline = [ // Stage 1: Complex filter combinations stages.filter() .ge("population", 100000) .and(stages.filter().le("population", 2000000)) .and(stages.filter() .eq("state", "California") .or(stages.filter().eq("state", "Texas")) .or(stages.filter().eq("state", "New York")) ) .ne("status", "inactive") .exists("coordinates"), // Stage 2: Advanced projection with exclusions and multiple reshapes stages.project() // Include specific fields .include("_id", "cityName", "state", "population", "coordinates") // Exclude sensitive or internal fields .exclude("internalId", "adminNotes", "tempData", "debugInfo") // Multiple complex reshape operations .reshape("populationCategory", expressions.text("Large City") ) .reshape("coordinatesSummary", expressions.concat( expressions.text("Lat: "), expressions.stringify(expressions.field("coordinates.lat")), expressions.text(", Lng: "), expressions.stringify(expressions.field("coordinates.lng")) ) ) .reshape("populationDensityEstimate", expressions.divide( expressions.field("population"), expressions.add( expressions.field("areaSquareMiles"), expressions.numeric(1) ) ) ) .reshape("isCoastal", expressions.text("Unknown") ) .reshape("regionCode", expressions.concat( expressions.toUpper(expressions.substring(expressions.field("state"), expressions.numeric(0), expressions.numeric(2))), expressions.text("-"), expressions.substring(expressions.field("cityName"), expressions.numeric(0), expressions.numeric(3)) ) ), // Stage 3: Filter based on computed fields stages.filter() .gt("populationDensityEstimate", 500) .ne("regionCode", ""), // Stage 4: Group by population category with advanced aggregations stages.group() .by(expressions.field("populationCategory"), "category") .by(expressions.field("state"), "state") .count("cityCount") .sum(expressions.field("population"), "totalPopulation") .avg(expressions.field("populationDensityEstimate"), "avgDensity") .max(expressions.field("population"), "largestCityPop") .min(expressions.field("population"), "smallestCityPop") .push(expressions.field("cityName"), "cityNames"), // Stage 5: Advanced projection on grouped data stages.project() .include("category", "state", "cityCount", "totalPopulation") .exclude("_id") .reshape("avgDensityRounded", expressions.floor(expressions.field("avgDensity"))) .reshape("populationRange", expressions.concat( expressions.stringify(expressions.field("smallestCityPop")), expressions.text(" - "), expressions.stringify(expressions.field("largestCityPop")) ) ) .reshape("avgCitySize", expressions.floor( expressions.divide( expressions.field("totalPopulation"), expressions.field("cityCount") ) ) ) .reshape("stateRegionId", expressions.concat( expressions.field("state"), expressions.text("_"), expressions.field("category") ) ), // Stage 6: Filter final results stages.filter() .ge("cityCount", 2) .gt("avgCitySize", 200000), // Stage 7: Limit results stages.limit(10), // Stage 8: Final sort stages.sort() .descending("totalPopulation") .ascending("state") ]; const builder = pipelineBuilder() .withStages(pipeline); const response = await wixClient.items.aggregatePipeline("CityAnalytics", builder.build()); /* Expected response format: * { * results: [ * { * "category": "Large City", * "state": "California", * "cityCount": 4, * "totalPopulation": 8542000, * "avgDensityRounded": 2847, * "populationRange": "873965 - 3971000", * "avgCitySize": 2135500, * "stateRegionId": "California_Large City" * }, * { * "category": "Large City", * "state": "Texas", * "cityCount": 3, * "totalPopulation": 4234000, * "avgDensityRounded": 1654, * "populationRange": "695000 - 2320000", * "avgCitySize": 1411333, * "stateRegionId": "Texas_Large City" * }, * { * "category": "Large City", * "state": "New York", * "cityCount": 2, * "totalPopulation": 8792000, * "avgDensityRounded": 8945, * "populationRange": "600000 - 8192000", * "avgCitySize": 4396000, * "stateRegionId": "New York_Large City" * } * ], * pagingMetadata: { * count: 3, * offset: 0, * total: 10, * cursors: { * next: "next_cursor_token", * prev: null * } * } * } */ ```