Query Patterns
This page covers query patterns for developers building on the MCP server or writing precise prompts. For natural-language use cases, see Use Cases.
Basic filtering
By signal type
{ collection: "signals", filter: { insightType: "decision" }}By date range
{ collection: "signals", filter: { createdAt: { $gte: { $date: "2025-01-01T00:00:00Z" }, $lt: { $date: "2025-02-01T00:00:00Z" } } }}By meeting status
{ collection: "meetings", filter: { status: "completed" }, sort: { end_time: -1 }}Nested field filters (dot notation)
{ collection: "signals", filter: { insightType: "action", "data.status": "pending", "data.priority": "high" }}Text search with regex
{ collection: "meetings", filter: { meeting_title: { $regex: "quarterly", $options: "i" } }}Projections
Return only the fields you need:
{ collection: "signals", filter: { insightType: "decision" }, projection: { "data.title": 1, "data.owner": 1, "data.impactLevel": 1, "citation.speaker": 1, createdAt: 1 }, sort: { createdAt: -1 }, limit: 20}Exclude large fields:
{ collection: "meetings", filter: { status: "completed" }, projection: { transcript: 0, recording_file: 0 }}Sorting and pagination
Sort by multiple fields
{ collection: "signals", filter: { insightType: "action" }, sort: { "data.priority": -1, createdAt: -1 }, limit: 25}Pagination with limit
The limit parameter caps results at 1–100 per query. For large result sets, combine with date-based or ID-based filtering to paginate.
Aggregation pipelines
Count signals by type
{ collection: "signals", pipeline: [ { $group: { _id: "$insightType", count: { $sum: 1 } } }, { $sort: { count: -1 } } ]}Signals per week
{ collection: "signals", pipeline: [ { $group: { _id: { week: { $isoWeek: "$createdAt" }, year: { $isoWeekYear: "$createdAt" } }, count: { $sum: 1 } } }, { $sort: { "_id.year": -1, "_id.week": -1 } }, { $limit: 12 } ]}Top speakers by signal count
{ collection: "signals", pipeline: [ { $match: { "citation.speaker": { $exists: true, $ne: "" } } }, { $group: { _id: "$citation.speaker", signals: { $sum: 1 }, decisions: { $sum: { $cond: [{ $eq: ["$insightType", "decision"] }, 1, 0] } }, actions: { $sum: { $cond: [{ $eq: ["$insightType", "action"] }, 1, 0] } } } }, { $sort: { signals: -1 } }, { $limit: 10 } ]}Signals by source platform
{ collection: "signals", pipeline: [ { $match: { sourceChannel: { $exists: true } } }, { $group: { _id: "$sourceChannel", count: { $sum: 1 } } }, { $sort: { count: -1 } } ]}Cross-collection lookup: signals with meeting details
{ collection: "signals", pipeline: [ { $match: { insightType: "decision", "data.impactLevel": "high" } }, { $lookup: { from: "meetings", localField: "sourceId", foreignField: "meeting_id", as: "meeting" } }, { $unwind: { path: "$meeting", preserveNullAndEmptyArrays: true } }, { $project: { "data.title": 1, "data.owner": 1, "citation.speaker": 1, "meeting.meeting_title": 1, "meeting.start_time": 1, createdAt: 1 } }, { $sort: { createdAt: -1 } }, { $limit: 20 } ]}Tips
Dot notation for nested fields
Signal content lives under data.* and citations under citation.*. Always use dot notation:
// correct"data.title""citation.speaker""citation.sourceLocation.startTime"
// incorrect — these won't match"data": { "title": "..." }Date handling
Dates in filters should use the $date operator or ISO 8601 strings:
{ createdAt: { $gte: { $date: "2025-01-15T00:00:00Z" } } }For relative dates (last 7 days, this month), describe the time range in natural language and let Claude compute the date values.
Array fields
For array fields like people, teams, participants, and userIds, use $in to check membership:
{ people: { $in: [ObjectId("...")] } }ObjectId fields
The _id, people, teams, initiative, project, and task fields are ObjectIds. When querying by ID, wrap values appropriately:
{ _id: ObjectId("64f1a2b3c4d5e6f7a8b9c0d1") }