Search Patterns¶
Advanced query techniques for CiviCRM.
Search by Custom Fields¶
# Custom fields use their API name
response = await client.get(
"Contact",
select=["id", "display_name", "custom_volunteer_status"],
where=[["custom_volunteer_status", "=", "Active"]],
)
Date Range Queries¶
from datetime import date, timedelta
# Contacts created in the last 30 days
cutoff = (date.today() - timedelta(days=30)).isoformat()
response = await client.get(
"Contact",
select=["id", "display_name", "created_date"],
where=[["created_date", ">=", cutoff]],
order_by={"created_date": "DESC"},
)
Pattern Matching¶
# Names starting with "Smith"
response = await client.get(
"Contact",
where=[["last_name", "LIKE", "Smith%"]],
)
# Email containing "gmail"
response = await client.get(
"Contact",
where=[["email_primary.email", "LIKE", "%gmail%"]],
)
Null Checks¶
# Contacts with email
response = await client.get(
"Contact",
where=[["email_primary.email", "IS NOT NULL", True]],
)
# Contacts without phone
response = await client.get(
"Contact",
where=[["phone_primary.phone", "IS NULL", True]],
)
Combining Conditions¶
All conditions in the where list are AND conditions:
response = await client.get(
"Contact",
where=[
["contact_type", "=", "Individual"],
["is_deleted", "=", False],
["email_primary.email", "IS NOT NULL", True],
["created_date", ">=", "2024-01-01"],
],
)
Performance Tips¶
Select only needed fields: Reduces data transfer
# Good: only get what you need select=["id", "display_name"] # Avoid: getting all fields select=None # default
Use limits: Avoid loading entire database
response = await client.get("Contact", limit=100)Filter early: Let CiviCRM filter, not your code
# Good: filter in query where=[["contact_type", "=", "Individual"]] # Avoid: filtering in Python after fetch