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.
tools/getOrdersByCustomerId.js
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.
{
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)
}
| 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) |
{
orders: Order[];
pagination: PaginationMetadata;
}
{
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
}
{
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)
}
// 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
// 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"
});
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`);
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}`);
});
Orders are filtered by building a customer reference path:
const customerPath = `Accounts/${accountId}/Customers/${customerId}`;
const options = {
orderBy: "orderId",
where: [["customer", "==", customerPath]],
...paginationOptions
};
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);
The tool transforms Firestore documents by:
id and full pathUses the shared executePaginatedQuery function with customer filtering, then transforms each order with populated references.
The tool validates that customerId is provided:
if (!customerId) {
throw new Error("The 'customerId' parameter is required.");
}
| 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 |
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}.`);
}
includeTotal: true adds an extra querycustomer field is indexed for optimal query performanceUse getOrdersByCustomerId when:
Use getOrders when:
Use getOrderById when:
/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)