Efficient batch processing for Spotlight searches
The batch operations module provides efficient ways to process multiple Spotlight searches in parallel or sequentially. Features include:
- Parallel search execution
- Sequential search execution
- Multi-directory searching
- Multi-query searching
- Result ordering preservation
import { QueryBuilder } from 'mdfind-node'
import { batchSearch } from 'mdfind-node'
const searches = [
{
query: new QueryBuilder().contentType('public.image').hasGPS().toString(),
options: { onlyInDirectory: '~/Pictures' }
},
{
query: new QueryBuilder().contentType('public.audio').toString(),
options: { onlyInDirectory: '~/Music' }
}
]
const results = await batchSearch(searches)
// results[0] contains image search results
// results[1] contains audio search resultsimport { batchSearchSequential } from 'mdfind-node'
const searches = [
{
query: 'kind:image',
options: { onlyInDirectory: '~/Pictures' }
},
{
query: 'kind:pdf',
options: { onlyInDirectory: '~/Documents' }
}
]
const results = await batchSearchSequential(searches)
// Results are processed one at a timeimport { mdfindMultiDirectory } from 'mdfind-node'
const query = new QueryBuilder()
.extension('ts')
.modifiedAfter(new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)) // Last week
.toString()
const directories = ['~/Documents', '~/Downloads', '~/Desktop']
const results = await mdfindMultiDirectory(query, directories)
// results[0] contains matches from Documents
// results[1] contains matches from Downloads
// results[2] contains matches from Desktopimport { mdfindMultiQuery } from 'mdfind-node'
const queries = [
new QueryBuilder().contentType('public.image').hasGPS().toString(),
new QueryBuilder().contentType('public.movie').toString(),
new QueryBuilder().contentType('com.adobe.pdf').toString()
]
const documentsPath = '~/Documents'
const results = await mdfindMultiQuery(queries, documentsPath)
// results[0] contains image matches
// results[1] contains movie matches
// results[2] contains PDF matchesAll search operations accept the standard mdfind options:
| Option | Type | Default | Description |
|---|---|---|---|
onlyInDirectory |
string |
- | Limit search to specific directory |
maxBuffer |
number |
1MB |
Maximum buffer size for results |
literal |
boolean |
false |
Disable special query interpretation |
interpret |
boolean |
false |
Enable natural language interpretation |
nullSeparator |
boolean |
false |
Use null character as separator |
reprint |
boolean |
false |
Reprint results in live mode |
- Use
batchSearchfor independent queries that can run in parallel - Use
batchSearchSequentialwhen order matters or for memory-intensive searches - Use
mdfindMultiDirectorywhen searching the same pattern across different locations - Use
mdfindMultiQuerywhen running multiple different searches in the same location - Set appropriate
maxBuffervalues for large result sets
import { QueryBuilder, batchSearch } from 'mdfind-node'
// Find different types of media files with specific criteria
const searches = [
{
query: new QueryBuilder()
.contentType('public.image')
.minImageDimensions(3000, 2000)
.hasGPS()
.toString(),
options: { onlyInDirectory: '~/Pictures' }
},
{
query: new QueryBuilder()
.contentType('public.audio')
.minAudioQuality(44100, 320000)
.inGenre('Classical')
.toString(),
options: { onlyInDirectory: '~/Music' }
},
{
query: new QueryBuilder()
.contentType('public.movie')
.largerThan(1024 * 1024 * 1024) // > 1GB
.toString(),
options: { onlyInDirectory: '~/Movies' }
}
]
const results = await batchSearch(searches)import { mdfindMultiQuery } from 'mdfind-node'
// Search for different types of development files
const queries = [
new QueryBuilder().isText().extension('ts').containing('QueryBuilder').toString(),
new QueryBuilder().isMarkdown().modifiedAfter(new Date('2024-01-01')).toString(),
new QueryBuilder().isJSON().containing('dependencies').toString(),
new QueryBuilder().isPlist().toString()
]
const projectDir = process.cwd()
const results = await mdfindMultiQuery(queries, projectDir)import { mdfindMultiDirectory } from 'mdfind-node'
// Search for documents across multiple locations
const query = new QueryBuilder()
.useOperator('||')
.isPDF()
.isMarkdown()
.modifiedAfter(new Date('2024-01-01'))
.toString()
const directories = ['~/Documents', '~/Downloads', '~/Desktop', '~/Library/Documentation']
const results = await mdfindMultiDirectory(query, directories)import { batchSearchSequential } from 'mdfind-node'
// Process memory-intensive searches one at a time
const searches = [
{
query: new QueryBuilder().contentType('public.image').minImageDimensions(4000, 3000).toString(),
options: {
onlyInDirectory: '~/Pictures',
maxBuffer: 10 * 1024 * 1024 // 10MB buffer
}
},
{
query: new QueryBuilder()
.contentType('public.movie')
.largerThan(2 * 1024 * 1024 * 1024) // > 2GB
.toString(),
options: {
onlyInDirectory: '~/Movies',
maxBuffer: 10 * 1024 * 1024 // 10MB buffer
}
}
]
const results = await batchSearchSequential(searches)-
Parallel vs Sequential
- Use
batchSearchfor independent, lightweight searches - Use
batchSearchSequentialfor memory-intensive operations - Consider system resources when setting concurrency
- Use
-
Buffer Management
- Set appropriate
maxBuffervalues based on expected result size - Use smaller buffers for many parallel searches
- Use larger buffers for sequential operations
- Set appropriate
-
Directory Scoping
- Always specify
onlyInDirectoryto limit search scope - Use
mdfindMultiDirectoryfor efficient multi-location searches - Consider directory size when organizing batch operations
- Always specify
-
Query Optimization
- Combine related queries with
useOperator('||') - Use specific content types and attributes
- Add date constraints to limit result sets
- Combine related queries with
import { batchSearch, MdfindError } from 'mdfind-node'
try {
const results = await batchSearch(searches)
} catch (error) {
if (error instanceof MdfindError) {
console.error('Search failed:', error.message)
console.error('stderr:', error.stderr)
} else {
console.error('Unexpected error:', error)
}
}import { batchSearch } from 'mdfind-node'
// Set timeouts for long-running searches
const timeout = setTimeout(() => {
// Cleanup logic
process.exit(1)
}, 30000)
try {
const results = await batchSearch(searches)
clearTimeout(timeout)
} catch (error) {
clearTimeout(timeout)
throw error
}- mdfind Documentation - Core search functionality
- Query Builder Documentation - Building search queries