Open luukee opened 5 days ago
Firestore does not have a full-text search capability by default. However, you can implement a basic search with queries that filter data by field values. For more advanced full-text search, you can integrate services like Algolia or ElasticSearch. In this example, I'll show how to implement a basic search based on field matching within the Firestore reports
collection.
Assume your reports
collection has fields like title
, description
, and tags
.
First, create a function that searches the Firestore reports
collection based on a search term (e.g., searching by title
or description
):
import { useState } from 'react'
import { db } from '../firebase' // Adjust to your Firebase config path
import { collection, query, where, getDocs } from 'firebase/firestore'
const searchReports = async (searchTerm) => {
const q = query(
collection(db, 'reports'),
where('title', '>=', searchTerm), // Start searching by title
where('title', '<=', searchTerm + '\uf8ff') // End range for search term
)
const querySnapshot = await getDocs(q)
let results = []
querySnapshot.forEach((doc) => {
results.push({ id: doc.id, ...doc.data() })
})
return results
}
This function queries the reports
collection, filtering by the title
field using Firestore's range queries. The \uf8ff
ensures it matches titles starting with the search term.
Now, create a SearchBar
component that will allow users to type in a search query and show the results.
import { useState } from 'react'
const SearchBar = () => {
const [searchTerm, setSearchTerm] = useState('')
const [searchResults, setSearchResults] = useState([])
const handleSearch = async (e) => {
e.preventDefault()
if (!searchTerm.trim()) return // Ignore empty searches
const results = await searchReports(searchTerm)
setSearchResults(results)
}
return (
<div>
<form onSubmit={handleSearch}>
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search reports..."
/>
<button type="submit">Search</button>
</form>
{/* Display search results */}
<ul>
{searchResults.map((result) => (
<li key={result.id}>{result.title}</li>
))}
</ul>
</div>
)
}
export default SearchBar
You can now import and use this SearchBar
component in any Next.js page where you'd like to offer search functionality:
import SearchBar from '../components/SearchBar'
const ReportsPage = () => {
return (
<div>
<h1>Search Reports</h1>
<SearchBar />
</div>
)
}
export default ReportsPage
For larger datasets or if you want to search multiple fields (e.g., title
, description
, tags
), you may want to consider using Firestore's array-contains
for tags or combining multiple queries, but this can get limited with Firestore's querying capabilities.
For more advanced searching (e.g., partial matching, fuzzy search), integrating with Algolia would be ideal, as it offers robust full-text search capabilities and can index your Firestore collection.
To avoid too many Firestore queries, you can implement debouncing so the query runs only after the user has stopped typing for a short period:
import { useState, useEffect } from 'react'
const SearchBar = () => {
const [searchTerm, setSearchTerm] = useState('')
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(searchTerm)
const [searchResults, setSearchResults] = useState([])
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedSearchTerm(searchTerm)
}, 300)
return () => {
clearTimeout(handler)
}
}, [searchTerm])
useEffect(() => {
if (debouncedSearchTerm) {
searchReports(debouncedSearchTerm).then(setSearchResults)
}
}, [debouncedSearchTerm])
return (
<div>
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search reports..."
/>
<ul>
{searchResults.map((result) => (
<li key={result.id}>{result.title}</li>
))}
</ul>
</div>
)
}
This ensures that Firestore queries are sent only after the user has paused typing for 300ms.
For Admin & Agency user login.
Test on the dev site: https://dev-truthsleuthlocal.netlify.app. The search bar should do a dynamic (as you type) search of the reports content.