The 3.0 native engine ships as @soulcraft/cor (brainy 8.x <-> cor 3.x are a version-matched pair); the old @soulcraft/cortex package stays on the 2.x/7.x line. Public docs and .d.ts-visible comments now name the correct package. Historical 2.x contract references (e.g. the 2.3.1 read-side fallback) keep the old name deliberately.
8 KiB
Query Operators (BFO)
Brainy Field Operators — the complete reference for
wherefilters infind().
All operators work with find({ where: { ... } }) and filter on metadata fields (not data).
Equality
| Operator | Alias | Description | Example |
|---|---|---|---|
eq |
equals |
Exact match | { status: { eq: 'active' } } |
ne |
notEquals |
Not equal | { status: { ne: 'deleted' } } |
Shorthand: A bare value is treated as equals:
// These are equivalent:
brain.find({ where: { status: 'active' } })
brain.find({ where: { status: { equals: 'active' } } })
Comparison
| Operator | Alias | Description | Example |
|---|---|---|---|
gt |
greaterThan |
Greater than | { age: { gt: 18 } } |
gte |
greaterThanOrEqual |
Greater or equal | { score: { gte: 90 } } |
lt |
lessThan |
Less than | { price: { lt: 100 } } |
lte |
lessThanOrEqual |
Less or equal | { rating: { lte: 3 } } |
between |
— | Inclusive range [min, max] |
{ year: { between: [2020, 2025] } } |
// Range query
const recent = await brain.find({
where: {
createdAt: { between: [Date.now() - 86400000, Date.now()] }
}
})
Array / Set
| Operator | Alias | Description | Example |
|---|---|---|---|
oneOf |
in |
Value is one of the given options | { color: { oneOf: ['red', 'blue'] } } |
noneOf |
— | Value is NOT one of the given options | { status: { noneOf: ['deleted', 'archived'] } } |
contains |
— | Array field contains value | { tags: { contains: 'ai' } } |
excludes |
— | Array field does NOT contain value | { tags: { excludes: 'spam' } } |
hasAll |
— | Array field contains ALL listed values | { skills: { hasAll: ['js', 'ts'] } } |
// Find entities tagged with 'ai'
const aiEntities = await brain.find({
where: { tags: { contains: 'ai' } }
})
// Find entities of specific types
const people = await brain.find({
where: { noun: { oneOf: ['Person', 'Agent'] } }
})
Existence
| Operator | Description | Example |
|---|---|---|
exists: true |
Field exists (has any value) | { email: { exists: true } } |
exists: false |
Field does NOT exist | { email: { exists: false } } |
missing: true |
Field does NOT exist (alias for exists: false) |
{ email: { missing: true } } |
missing: false |
Field exists (alias for exists: true) |
{ email: { missing: false } } |
// Find entities that have an email field
const withEmail = await brain.find({
where: { email: { exists: true } }
})
Pattern (In-Memory Only)
These operators work via the in-memory filter path. They are applied after the indexed query, so use them with other indexed operators for best performance.
| Operator | Description | Example |
|---|---|---|
matches |
Regex or string pattern match | { name: { matches: /^Dr\./ } } |
startsWith |
String prefix | { name: { startsWith: 'John' } } |
endsWith |
String suffix | { email: { endsWith: '@gmail.com' } } |
const doctors = await brain.find({
where: {
type: NounType.Person, // Indexed — fast
name: { startsWith: 'Dr.' } // In-memory — applied after
}
})
Logical
Combine multiple conditions:
| Operator | Description | Example |
|---|---|---|
allOf |
ALL sub-filters must match (AND) | { allOf: [{ status: 'active' }, { role: 'admin' }] } |
anyOf |
ANY sub-filter must match (OR) | { anyOf: [{ role: 'admin' }, { role: 'owner' }] } |
not |
Invert a filter | { not: { status: 'deleted' } } |
// Complex OR query
const adminsOrOwners = await brain.find({
where: {
anyOf: [
{ role: 'admin' },
{ role: 'owner' }
]
}
})
// NOT query
const notDeleted = await brain.find({
where: {
not: { status: 'deleted' }
}
})
// Combined AND + OR
const results = await brain.find({
where: {
allOf: [
{ department: 'engineering' },
{ anyOf: [
{ level: 'senior' },
{ yearsExperience: { greaterThan: 5 } }
]}
]
}
})
Indexed vs In-Memory Operators
Brainy's MetadataIndex supports a subset of operators natively for O(1) field lookups. Other operators fall back to in-memory filtering.
| Operator | MetadataIndex (Indexed) | In-Memory Fallback |
|---|---|---|
equals / eq |
Yes | Yes |
notEquals / ne |
— | Yes |
greaterThan / gt |
Yes | Yes |
greaterThanOrEqual / gte |
Yes | Yes |
lessThan / lt |
Yes | Yes |
lessThanOrEqual / lte |
Yes | Yes |
between |
Yes | Yes |
oneOf / in |
Yes | Yes |
noneOf |
— | Yes |
contains |
Yes | Yes |
exists / missing |
Yes | Yes |
matches |
— | Yes |
startsWith |
— | Yes |
endsWith |
— | Yes |
allOf |
Partial | Yes |
anyOf |
Partial | Yes |
not |
— | Yes |
Performance tip: Combine indexed operators (equals, greaterThan, oneOf, between, contains, exists) with pattern operators for optimal speed — the index narrows results first, then patterns filter in memory.
Practical Examples
Filter by entity type
// Using the type shorthand (recommended)
brain.find({ type: NounType.Person })
// Using where.noun directly
brain.find({ where: { noun: NounType.Person } })
// Multiple types
brain.find({ type: [NounType.Person, NounType.Agent] })
Filter by subtype
subtype is a top-level standard field — takes the column-store fast path, not the metadata fallback. Pair with type for the typical "Person who is an employee" query:
// Equality on subtype:
brain.find({ type: NounType.Person, subtype: 'employee' })
// Set membership:
brain.find({ type: NounType.Person, subtype: ['employee', 'contractor'] })
// Operator-form predicates use `where`:
brain.find({
type: NounType.Person,
where: { subtype: { exists: true } }
})
See the Subtypes & Facets guide for the full surface.
Filter relationships by subtype (7.30+)
Verbs are first-class peers — related() and graph traversal both honor subtype filters on the fast path:
// Filter relationships by VerbType subtype
const direct = await brain.related({
from: ceoId,
type: VerbType.ReportsTo,
subtype: 'direct'
})
// Set membership on verb subtype
const all = await brain.related({
from: ceoId,
type: VerbType.ReportsTo,
subtype: ['direct', 'dotted-line']
})
// Graph traversal — subtype filters traversal edges (depth-1 in 7.30 JS path;
// multi-hop subtype filtering lands on Cor native)
const reports = await brain.find({
connected: {
from: ceoId,
via: VerbType.ReportsTo,
subtype: 'direct',
depth: 1
}
})
Combine semantic search with filters
const results = await brain.find({
query: 'machine learning engineer', // Semantic search (on data)
type: NounType.Person, // Type filter (indexed)
where: {
department: 'engineering', // Exact match (indexed)
yearsExperience: { greaterThan: 3 } // Range filter (indexed)
},
limit: 10
})
Temporal queries
const lastWeek = Date.now() - 7 * 24 * 60 * 60 * 1000
const recentEntities = await brain.find({
where: {
createdAt: { greaterThan: lastWeek }
},
orderBy: 'createdAt',
order: 'desc',
limit: 50
})
Graph + metadata combination
const results = await brain.find({
connected: {
from: teamLeadId,
via: VerbType.WorksWith,
depth: 2
},
where: {
role: { oneOf: ['engineer', 'designer'] },
active: true
}
})
See Also
- Data Model — Entity structure, data vs metadata
- API Reference — Complete API documentation
- Find System — Natural language find() details