firestore-query-collection-parameterizable

Query a Firestore collection with parameterizable filters and Firestore native JSON value types

Overview

The firestore-query-collection-parameterizable tool allows you to query Firestore collections with dynamic, parameterizable filters that support Firestore’s native JSON value types. This tool is particularly useful when you need to create reusable query templates with parameters that can be substituted at runtime.

Key Features

  • Parameterizable Queries: Use Go template syntax to create dynamic queries
  • Native JSON Value Types: Support for Firestore’s typed values (stringValue, integerValue, doubleValue, etc.)
  • Complex Filter Logic: Support for AND/OR logical operators in filters
  • Template Substitution: Dynamic collection paths, filters, and ordering
  • Query Analysis: Optional query performance analysis with explain metrics

Configuration

Basic Configuration

tools:
  query_countries:
    kind: firestore-query-collection-parameterizable
    source: my-firestore-source
    description: Query countries with dynamic filters
    collectionPath: "countries"
    filters: |
      {
        "field": "continent",
        "op": "==",
        "value": {"stringValue": "{{.continent}}"}
      }
    parameters:
      - name: continent
        type: string
        description: Continent to filter by
        required: true

Advanced Configuration with Complex Filters

tools:
  advanced_query:
    kind: firestore-query-collection-parameterizable
    source: my-firestore-source
    description: Advanced query with complex filters
    collectionPath: "{{.collection}}"
    filters: |
      {
        "or": [
          {"field": "status", "op": "==", "value": {"stringValue": "{{.status}}"}},
          {
            "and": [
              {"field": "priority", "op": ">", "value": {"integerValue": "{{.priority}}"}},
              {"field": "area", "op": "<", "value": {"doubleValue": {{.maxArea}}}},
              {"field": "active", "op": "==", "value": {"booleanValue": {{.isActive}}}}
            ]
          }
        ]
      }
    select:
      - name
      - status
      - priority
    orderBy:
      field: "{{.sortField}}"
      direction: "{{.sortDirection}}"
    limit: 100
    analyzeQuery: true
    parameters:
      - name: collection
        type: string
        description: Collection to query
        required: true
      - name: status
        type: string
        description: Status to filter by
        required: true
      - name: priority
        type: string
        description: Minimum priority value
        required: true
      - name: maxArea
        type: float
        description: Maximum area value
        required: true
      - name: isActive
        type: boolean
        description: Filter by active status
        required: true
      - name: sortField
        type: string
        description: Field to sort by
        required: false
        default: "createdAt"
      - name: sortDirection
        type: string
        description: Sort direction (ASCENDING or DESCENDING)
        required: false
        default: "DESCENDING"

Parameters

Configuration Parameters

ParameterTypeRequiredDescription
kindstringYesMust be firestore-query-collection-parameterizable
sourcestringYesName of the Firestore source to use
descriptionstringYesDescription of what this tool does
collectionPathstringYesPath to the collection (supports templates)
filtersstringNoJSON string defining query filters (supports templates)
selectarrayNoFields to select from documents(supports templates - string or array)
orderByobjectNoOrdering configuration with field and direction(supports templates for the value of field or direction)
limitintegerNoMaximum number of documents to return (default: 100) (supports templates)
analyzeQuerybooleanNoWhether to analyze query performance (default: false) (supports templates)
parametersarrayYesParameter definitions for template substitution

Runtime Parameters

Runtime parameters are defined in the parameters array and can be used in templates throughout the configuration.

Filter Format

Simple Filter

{
  "field": "age",
  "op": ">",
  "value": {"integerValue": "25"}
}

AND Filter

{
  "and": [
    {"field": "status", "op": "==", "value": {"stringValue": "active"}},
    {"field": "age", "op": ">=", "value": {"integerValue": "18"}}
  ]
}

OR Filter

{
  "or": [
    {"field": "role", "op": "==", "value": {"stringValue": "admin"}},
    {"field": "role", "op": "==", "value": {"stringValue": "moderator"}}
  ]
}

Nested Filters

{
  "or": [
    {"field": "type", "op": "==", "value": {"stringValue": "premium"}},
    {
      "and": [
        {"field": "type", "op": "==", "value": {"stringValue": "standard"}},
        {"field": "credits", "op": ">", "value": {"integerValue": "1000"}}
      ]
    }
  ]
}

Firestore Native Value Types

The tool supports all Firestore native JSON value types:

TypeFormatExample
String{"stringValue": "text"}{"stringValue": "{{.name}}"}
Integer{"integerValue": "123"} or {"integerValue": 123}{"integerValue": "{{.age}}"} or {"integerValue": {{.age}}}
Double{"doubleValue": 45.67}{"doubleValue": {{.price}}}
Boolean{"booleanValue": true}{"booleanValue": {{.active}}}
Null{"nullValue": null}{"nullValue": null}
Timestamp{"timestampValue": "RFC3339"}{"timestampValue": "{{.date}}"}
GeoPoint{"geoPointValue": {"latitude": 0, "longitude": 0}}See below
Array{"arrayValue": {"values": [...]}}See below
Map{"mapValue": {"fields": {...}}}See below

Complex Type Examples

GeoPoint:

{
  "field": "location",
  "op": "==",
  "value": {
    "geoPointValue": {
      "latitude": 37.7749,
      "longitude": -122.4194
    }
  }
}

Array:

{
  "field": "tags",
  "op": "array-contains",
  "value": {"stringValue": "{{.tag}}"}
}

Supported Operators

  • < - Less than
  • <= - Less than or equal
  • > - Greater than
  • >= - Greater than or equal
  • == - Equal
  • != - Not equal
  • array-contains - Array contains value
  • array-contains-any - Array contains any of the values
  • in - Value is in array
  • not-in - Value is not in array

Examples

Example 1: Query with Dynamic Collection Path

tools:
  user_documents:
    kind: firestore-query-collection-parameterizable
    source: my-firestore
    description: Query user-specific documents
    collectionPath: "users/{{.userId}}/documents"
    filters: |
      {
        "field": "type",
        "op": "==",
        "value": {"stringValue": "{{.docType}}"}
      }
    parameters:
      - name: userId
        type: string
        description: User ID
        required: true
      - name: docType
        type: string
        description: Document type to filter
        required: true

Example 2: Complex Geographic Query

tools:
  location_search:
    kind: firestore-query-collection-parameterizable
    source: my-firestore
    description: Search locations by area and population
    collectionPath: "cities"
    filters: |
      {
        "and": [
          {"field": "country", "op": "==", "value": {"stringValue": "{{.country}}"}},
          {"field": "population", "op": ">", "value": {"integerValue": "{{.minPopulation}}"}},
          {"field": "area", "op": "<", "value": {"doubleValue": {{.maxArea}}}}
        ]
      }
    orderBy:
      field: "population"
      direction: "DESCENDING"
    limit: 50
    parameters:
      - name: country
        type: string
        description: Country code
        required: true
      - name: minPopulation
        type: string
        description: Minimum population (as string for large numbers)
        required: true
      - name: maxArea
        type: float
        description: Maximum area in square kilometers
        required: true

Example 3: Time-based Query with Analysis

tools:
  activity_log:
    kind: firestore-query-collection-parameterizable
    source: my-firestore
    description: Query activity logs within time range
    collectionPath: "logs"
    filters: |
      {
        "and": [
          {"field": "timestamp", "op": ">=", "value": {"timestampValue": "{{.startTime}}"}},
          {"field": "timestamp", "op": "<=", "value": {"timestampValue": "{{.endTime}}"}},
          {"field": "severity", "op": "in", "value": {"arrayValue": {"values": [
            {"stringValue": "ERROR"},
            {"stringValue": "CRITICAL"}
          ]}}}
        ]
      }
    select:
      - timestamp
      - message
      - severity
      - userId
    orderBy:
      field: "timestamp"
      direction: "DESCENDING"
    analyzeQuery: true
    parameters:
      - name: startTime
        type: string
        description: Start time in RFC3339 format
        required: true
      - name: endTime
        type: string
        description: End time in RFC3339 format
        required: true

Usage

Invoking the Tool

# Using curl
curl -X POST http://localhost:5000/api/tool/your-tool-name/invoke \
  -H "Content-Type: application/json" \
  -d '{
    "continent": "Europe",
    "minPopulation": "1000000",
    "maxArea": 500000.5,
    "isActive": true
  }'

Response Format

Without analyzeQuery:

[
  {
    "id": "doc1",
    "path": "countries/doc1",
    "data": {
      "name": "France",
      "continent": "Europe",
      "population": 67000000,
      "area": 551695
    },
    "createTime": "2024-01-01T00:00:00Z",
    "updateTime": "2024-01-15T10:30:00Z"
  }
]

With analyzeQuery:

{
  "documents": [...],
  "explainMetrics": {
    "planSummary": {
      "indexesUsed": [...]
    },
    "executionStats": {
      "resultsReturned": 10,
      "executionDuration": "15ms",
      "readOperations": 10
    }
  }
}

Best Practices

  1. Use Typed Values: Always use Firestore’s native JSON value types for proper type handling
  2. String Numbers for Large Integers: Use string representation for large integers to avoid precision loss
  3. Template Security: Validate all template parameters to prevent injection attacks
  4. Index Optimization: Use analyzeQuery to identify missing indexes
  5. Limit Results: Always set a reasonable limit to prevent excessive data retrieval
  6. Field Selection: Use select to retrieve only necessary fields

Limitations

  • Maximum of 100 filters per query (configurable)
  • Template parameters must be properly escaped in JSON contexts
  • Complex nested queries may require composite indexes

See Also

Last modified September 4, 2025: minor change (22b5a567d)