Skip to content

groupByMultiple Method

The groupByMultiple() method groups collection items by multiple keys, creating composite groups. Returns a Map where keys are combined key values separated by '::' and values are collections of matching items.

Basic Syntax

typescript
collect(items).groupByMultiple(...keys: K[]): Map<string, Collection<T>>

Examples

Basic Usage

typescript
import { collect } from 'ts-collect'

// Simple grouping by multiple fields
const items = collect([
  { category: 'A', status: 'active', type: '1' },
  { category: 'A', status: 'inactive', type: '2' },
  { category: 'B', status: 'active', type: '1' }
])

const grouped = items.groupByMultiple('category', 'status')
// Map(3) {
//   'A::active' => Collection[{category: 'A', status: 'active', type: '1'}],
//   'A::inactive' => Collection[{category: 'A', status: 'inactive', type: '2'}],
//   'B::active' => Collection[{category: 'B', status: 'active', type: '1'}]
// }

Working with Objects

typescript
interface Product {
  id: string
  category: string
  brand: string
  status: 'active' | 'discontinued'
}

const products = collect<Product>([
  { id: '1', category: 'electronics', brand: 'Apple', status: 'active' },
  { id: '2', category: 'electronics', brand: 'Samsung', status: 'active' },
  { id: '3', category: 'electronics', brand: 'Apple', status: 'discontinued' }
])

// Group by category and brand
const groupedProducts = products.groupByMultiple('category', 'brand', 'status')

Real-world Examples

Product Analytics System

typescript
interface SalesData {
  productId: string
  category: string
  region: string
  channel: string
  revenue: number
  units: number
}

class SalesAnalyzer {
  constructor(private sales: Collection<SalesData>) {}

  getSegmentedAnalysis(): Map<string, {
    revenue: number
    units: number
    averageOrderValue: number
  }> {
    const grouped = this.sales.groupByMultiple('category', 'region', 'channel')
    const analysis = new Map()

    grouped.forEach((segment, key) => {
      analysis.set(key, {
        revenue: segment.sum('revenue'),
        units: segment.sum('units'),
        averageOrderValue: segment.avg('revenue')
      })
    })

    return analysis
  }

  getTopPerformingSegments(limit: number = 5): Array<{
    segment: string
    metrics: {
      revenue: number
      units: number
    }
  }> {
    const analysis = this.getSegmentedAnalysis()

    return Array.from(analysis.entries())
      .sort((a, b) => b[1].revenue - a[1].revenue)
      .slice(0, limit)
      .map(([segment, metrics]) => ({
        segment,
        metrics: {
          revenue: metrics.revenue,
          units: metrics.units
        }
      }))
  }
}

Inventory Management System

typescript
interface InventoryItem {
  sku: string
  warehouse: string
  zone: string
  category: string
  quantity: number
  reorderPoint: number
}

class InventoryManager {
  constructor(private inventory: Collection<InventoryItem>) {}

  getStockLevelsByLocation(): Map<string, {
    totalQuantity: number
    itemsNeedingReorder: number
    utilizationRate: number
  }> {
    const grouped = this.inventory.groupByMultiple('warehouse', 'zone', 'category')
    const analysis = new Map()

    grouped.forEach((items, location) => {
      const totalQuantity = items.sum('quantity')
      const itemsNeedingReorder = items
        .filter(item => item.quantity <= item.reorderPoint)
        .count()

      analysis.set(location, {
        totalQuantity,
        itemsNeedingReorder,
        utilizationRate: this.calculateUtilization(items)
      })
    })

    return analysis
  }

  findLowStockLocations(): Array<{
    location: string
    items: InventoryItem[]
  }> {
    const grouped = this.inventory.groupByMultiple('warehouse', 'zone')
    const lowStock: Array<{location: string, items: InventoryItem[]}> = []

    grouped.forEach((items, location) => {
      const needingReorder = items
        .filter(item => item.quantity <= item.reorderPoint)
        .toArray()

      if (needingReorder.length > 0) {
        lowStock.push({
          location,
          items: needingReorder
        })
      }
    })

    return lowStock
  }

  private calculateUtilization(items: Collection<InventoryItem>): number {
    const totalCapacity = items.count() * 100 // Example capacity calculation
    const currentStock = items.sum('quantity')
    return (currentStock / totalCapacity) * 100
  }
}

Advanced Usage

Customer Segmentation System

typescript
interface CustomerData {
  id: string
  region: string
  segment: string
  industry: string
  spendingTier: 'low' | 'medium' | 'high'
  engagementLevel: 'active' | 'inactive'
}

class CustomerSegmentAnalyzer {
  constructor(private customers: Collection<CustomerData>) {}

  analyzeSegments(): {
    segments: Map<string, CustomerData[]>
    metrics: Map<string, {
      count: number
      activeRatio: number
      spendingDistribution: Record<string, number>
    }>
  } {
    const segments = this.customers.groupByMultiple(
      'region',
      'segment',
      'industry',
      'spendingTier'
    )

    const metrics = new Map()

    segments.forEach((customers, segmentKey) => {
      metrics.set(segmentKey, {
        count: customers.count(),
        activeRatio: this.calculateActiveRatio(customers),
        spendingDistribution: this.calculateSpendingDistribution(customers)
      })
    })

    return {
      segments,
      metrics
    }
  }

  findHighValueSegments(): Array<{
    segment: string
    customers: CustomerData[]
    metrics: {
      totalCustomers: number
      activeCustomers: number
      highSpendingRatio: number
    }
  }> {
    const segments = this.customers.groupByMultiple('region', 'industry')
    const highValue: Array<{
      segment: string
      customers: CustomerData[]
      metrics: any
    }> = []

    segments.forEach((customers, segment) => {
      const activeHighSpending = customers.filter(c =>
        c.engagementLevel === 'active' &&
        c.spendingTier === 'high'
      ).count()

      const ratio = activeHighSpending / customers.count()

      if (ratio > 0.3) { // 30% threshold for high-value segment
        highValue.push({
          segment,
          customers: customers.toArray(),
          metrics: {
            totalCustomers: customers.count(),
            activeCustomers: customers
              .where('engagementLevel', 'active')
              .count(),
            highSpendingRatio: ratio
          }
        })
      }
    })

    return highValue
  }

  private calculateActiveRatio(customers: Collection<CustomerData>): number {
    const active = customers
      .where('engagementLevel', 'active')
      .count()
    return active / customers.count()
  }

  private calculateSpendingDistribution(
    customers: Collection<CustomerData>
  ): Record<string, number> {
    const distribution: Record<string, number> = {
      low: 0,
      medium: 0,
      high: 0
    }

    customers.groupBy('spendingTier')
      .forEach((group, tier) => {
        distribution[tier] = group.count() / customers.count()
      })

    return distribution
  }
}

Type Safety

typescript
interface TypedItem {
  id: number
  category: string
  subCategory: string
  status: 'active' | 'inactive'
}

const items = collect<TypedItem>([
  { id: 1, category: 'A', subCategory: 'X', status: 'active' },
  { id: 2, category: 'A', subCategory: 'Y', status: 'inactive' }
])

// Type-safe multiple grouping
const grouped: Map<string, Collection<TypedItem>> = items.groupByMultiple(
  'category',
  'subCategory',
  'status'
)

// TypeScript enforces valid keys
// items.groupByMultiple('invalid')  // ✗ TypeScript error

Return Value

  • Returns a Map with composite keys and Collection values
  • Composite keys are joined with '::'
  • Original collection remains unchanged
  • Maintains type safety with TypeScript
  • Can be chained with other collection methods
  • Groups maintain original item references

Common Use Cases

1. Product Organization

  • Category hierarchies
  • Stock management
  • Pricing structures
  • Feature grouping
  • Variant organization

2. Sales Analysis

  • Multi-dimensional analysis
  • Performance tracking
  • Revenue grouping
  • Channel analysis
  • Market segmentation

3. Inventory Management

  • Location tracking
  • Stock categorization
  • Supply organization
  • Storage optimization
  • Distribution management

4. Customer Segmentation

  • Market analysis
  • Behavior grouping
  • Profile categorization
  • Targeting analysis
  • Preference grouping

5. Order Processing

  • Status tracking
  • Fulfillment grouping
  • Shipping organization
  • Priority management
  • Process categorization

6. Performance Analytics

  • Multi-metric analysis
  • Trend grouping
  • Pattern recognition
  • Comparison analysis
  • Benchmark grouping

7. Content Management

  • Category organization
  • Tag grouping
  • Status tracking
  • Access management
  • Version control

8. User Management

  • Role organization
  • Permission grouping
  • Access control
  • Activity tracking
  • Profile management

9. Reporting Systems

  • Data organization
  • Metric grouping
  • Result categorization
  • Analysis structuring
  • Comparison grouping

10. Resource Management

  • Allocation tracking
  • Usage categorization
  • Availability grouping
  • Capacity management
  • Distribution analysis

Released under the MIT License.