Litelead-mcp

getOrdersByCustomerId Tool

Overview

The getOrdersByCustomerId tool retrieves order records for a specific customer from the Firebase/Firestore database with support for pagination, sorting, and automatic population of related references.

Location

tools/getOrdersByCustomerId.js

Description

Retrieves all orders for a specific customer with cursor-based pagination support. Orders are filtered by customer reference path and include populated customer, contact, and staff data. Orders are retrieved from the Firestore path: /Accounts/{accountId}/Orders.

Input Schema

{
  customerId: string;                    // REQUIRED: Customer document ID
  limit?: number;                        // Number of records to retrieve (1-100, default: 50)
  cursor?: string;                       // Document ID for cursor-based pagination
  orderBy?: string;                      // Field to order by (default: "orderId")
  orderDirection?: "asc" | "desc";       // Sort direction (default: "asc")
  cursorDirection?: "next" | "previous"; // Direction for pagination (default: "next")
  includeTotal?: boolean;                // Include total count of all orders (default: false)
}

Parameters

Parameter Type Required Default Description
customerId string Yes - Customer document ID to fetch orders for
limit number No 50 Maximum number of orders to return (1-100)
cursor string No - Document ID to start pagination from
orderBy string No “orderId” Field name to sort by
orderDirection enum No “asc” Sort direction: “asc” or “desc”
cursorDirection enum No “next” Pagination direction: “next” or “previous”
includeTotal boolean No false Whether to include total count (expensive)

Output Schema

{
  orders: Order[];
  pagination: PaginationMetadata;
}

Order Object

{
  id: string;                        // Firestore document ID
  path: string;                      // Full Firestore path
  orderId: number;                   // Unique order ID
  title: string;                     // Order title
  description: string;               // Order description
  stage: number;                     // Order stage/status number
  closed: boolean;                   // Whether order is closed
  createdAt: string | Date;          // Creation timestamp (locale string)
  lastCommentAt: string | Date;      // Last comment timestamp (locale string)
  deadline?: string | Date;          // Deadline (locale string)
  customer: Customer | null;         // Populated customer object
  contact: Contact | null;           // Populated contact object
  technician_staff: Staff | null;    // Populated technician staff object
  responsible_staff: Staff | null;   // Populated responsible staff object
  // ... other order fields
}

Pagination Metadata

{
  limit: number;                 // Applied limit
  hasMore: boolean;              // Whether more results exist
  nextCursor: string | null;     // Cursor for next page
  previousCursor: string | null; // Cursor for previous page
  total?: number | null;         // Total count (if includeTotal was true)
}

Usage Examples

Basic Usage

// Get first 10 orders for a customer
const result = await getOrdersByCustomerId(context, {
  customerId: "customer123",
  limit: 10
});

console.log(result.orders);        // Array of 10 orders with populated references
console.log(result.pagination);    // Pagination metadata

Paginated Retrieval

// First page
const page1 = await getOrdersByCustomerId(context, {
  customerId: "customer123",
  limit: 20,
  orderBy: "createdAt",
  orderDirection: "desc"
});

// Next page
const page2 = await getOrdersByCustomerId(context, {
  customerId: "customer123",
  limit: 20,
  cursor: page1.pagination.nextCursor,
  cursorDirection: "next"
});

// Previous page
const page1Again = await getOrdersByCustomerId(context, {
  customerId: "customer123",
  limit: 20,
  cursor: page2.pagination.previousCursor,
  cursorDirection: "previous"
});

With Total Count

const result = await getOrdersByCustomerId(context, {
  customerId: "customer123",
  limit: 10,
  includeTotal: true
});

console.log(`Customer has ${result.pagination.total} total orders`);
console.log(`Showing ${result.orders.length} orders`);

Accessing Populated Data

const result = await getOrdersByCustomerId(context, {
  customerId: "customer123",
  limit: 5
});

result.orders.forEach(order => {
  console.log(`Order #${order.orderId}: ${order.title}`);
  console.log(`Customer: ${order.customer?.name}`);
  console.log(`Contact: ${order.contact?.email}`);
  console.log(`Technician: ${order.technician_staff?.name}`);
  console.log(`Responsible: ${order.responsible_staff?.name}`);
});

Implementation Details

Customer Filtering

Orders are filtered by building a customer reference path:

const customerPath = `Accounts/${accountId}/Customers/${customerId}`;
const options = {
  orderBy: "orderId",
  where: [["customer", "==", customerPath]],
  ...paginationOptions
};

Reference Population

Each order automatically fetches and populates related documents:

const customer = await getDocument(db, orderData.customer);
const contact = await getDocument(db, orderData.contact);
const technician = await getDocumentById(db, `Accounts/${accountId}/Staff`, orderData.technician_staff);
const responsible = await getDocumentById(db, `Accounts/${accountId}/Staff`, orderData.responsible_staff);

Data Transformation

The tool transforms Firestore documents by:

  1. Adding the document id and full path
  2. Converting timestamps to locale strings (de-DE format)
  3. Populating all reference fields with full documents
  4. Handling missing references gracefully (sets to null)

Pagination Logic

Uses the shared executePaginatedQuery function with customer filtering, then transforms each order with populated references.

Validation

The tool validates that customerId is provided:

if (!customerId) {
  throw new Error("The 'customerId' parameter is required.");
}

Error Handling

Common Errors

Error Cause Solution
“The ‘customerId’ parameter is required.” Missing customerId Provide customerId in params
“Failed to fetch orders for customer [id].” Firestore error Check Firebase connection and permissions

Error Response

Errors are logged with the customer ID and re-thrown:

catch (error) {
  console.error(`Error fetching orders for customer ${customerId}:`, error);
  throw new Error(`Failed to fetch orders for customer ${customerId}.`);
}

Performance Considerations

  1. Multiple Queries: Each order triggers up to 4 additional reads for references
  2. Async Population: References are populated after pagination, not during
  3. Limit Recommendations: Keep limit reasonable (10-50) to manage reference fetching overhead
  4. Total Count: Setting includeTotal: true adds an extra query
  5. Use Case: Best when you need complete order information for a customer
  6. Customer Filtering: Ensure the customer field is indexed for optimal query performance

When to Use

Use getOrdersByCustomerId when:

Use getOrders when:

Use getOrderById when:

Firestore Collection Structure

/Accounts/{accountId}/Orders/{orderId}
  - orderId: number
  - title: string
  - description: string
  - stage: number
  - closed: boolean
  - createdAt: timestamp
  - lastCommentAt: timestamp
  - deadline: timestamp
  - customer: string (reference path - used for filtering)
  - contact: string (reference path)
  - technician_staff: string (staff ID)
  - responsible_staff: string (staff ID)

See Also