content icon indicating copy to clipboard operation
content copied to clipboard

Searching for a text in markdown

Open NenadP opened this issue 3 years ago • 3 comments

Hi, I am not seeing this in the docs, or maybe its not apparent to me.

Is it possible to search for a text anywhere if I had markdown files?

Say I have a bunch of markdown .md files in my content dir, and I would like to present a separate page to search anywhere in these md files?

In my case:

  • user would search by search term
  • that searches anywhere in .md files in content directory
  • I preset user the list of page titles and a little excerpt from the page where match was found

Questions:

  • if this is presently achievable, and if yes, how?
  • inf not, if its possible to put it on a feature request list?

NenadP avatar Sep 07 '22 21:09 NenadP

I am looking at the queries, I guess there is body with all of its children but that is likely hard to search.

A workaround would be to provide a custom field in .md files

---
bodyPlainText: ... // copy of all the text without markdown in the md document
---

And then use query content:

const articles = await queryContent()
  .where({ bodyPlainText: { $contains: ['my search text'] } })
  .find()

but bodyPlainText and its value would need to be built programmatically.

(this is obviously naive approach, lots of things to consider like ordering best results etc.)

NenadP avatar Sep 07 '22 22:09 NenadP

Supporting full-text search is not planned yet. To generate bodyPlainText for contents you can use transformers.

farnabaz avatar Sep 12 '22 14:09 farnabaz

@farnabaz yeah, I figured so. Depending on the requirement it could be searched also by traversing trees like so:

 // getting all the articles - I guess this approach would be very computational intensive if there is a large amount
 // of content to be searched on the client side and not using something like Algolia
 // In the below code example, all results are aggregated per `_path` (so per page). 
 // But could be easily modified to  a different strategy
 // The search match is wrapped inside the <strong> tag so it could be highlighted (needs to be interpolated with `v-html`)

 // Handy lib for traversing trees
 import { visit } from 'unist-util-visit'

 const articles = await queryContent().find()
 const searchResults = ref([])

 const getSearchResults = (searchTerm: string) => {
    searchResults.value = []
    const searchTermLowerCase = searchTerm.toLocaleLowerCase()
    articles.forEach((article: ParsedContent) => {
      visit(article.body, 'text', (node) => {
        if (node.value.toLocaleLowerCase().includes(searchTermLowerCase)) {
          const existingPageResult = searchResults.value.find(
            (result) => result.path === article._path
          )
          const searchResult = node.value.replaceAll(
            new RegExp(searchTermLowerCase, 'gi'),
            (match) => `<strong>${match}</strong>`
          )
          if (existingPageResult) {
            existingPageResult.searchResult += `<br />${searchResult }`
          } else {
            searchResults.value.push({
              title: article.title,
              searchResult 
            })
          }
        }
      })
    })
  }

NenadP avatar Sep 12 '22 18:09 NenadP