I'm using Algolia for adding search to my JAMStack website. however, my site has some sort of premium content and I want them to be searchable while remaining hidden to the users.
I can achieve similar functionality by adding the body
attribute to the searchable fields and remove it from the retrieved attributes. this way Algolia will still search the body for occurrences of the query while not exposing them to the user.
But the more preferable behavior is for the user to be able to see one or two occurrences of what he searched for in the retrieved body, but not able to see the whole text of the premium content.
For example, let's say we have the following entities in our index:
[
{
title: "Hello",
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
title: "Hi",
body: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit"
}
]
Now, if I query the algolia API with text "i", algolia response looks like this:
...
hits: [
{
title: "Hello",
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
_highlightResults: {
body: "Lorem <em>i</em>psum dolor s<em>i</em>t amet, consectetur ad<em>i</em>p<em>i</em>sc<em>i</em>ng el<em>i</em>t, sed do e<em>i</em>usmod tempor <em>i</em>nc<em>i</em>d<em>i</em>dunt ut labore et dolore magna al<em>i</em>qua. Ut en<em>i</em>m ad m<em>i</em>n<em>i</em>m ven<em>i</em>am, qu<em>i</em>s nostrud exerc<em>i</em>tat<em>i</em>on ullamco labor<em>i</em>s n<em>i</em>s<em>i</em> ut al<em>i</em>qu<em>i</em>p ex ea commodo consequat. Du<em>i</em>s aute <em>i</em>rure dolor <em>i</em>n reprehender<em>i</em>t <em>i</em>n voluptate vel<em>i</em>t esse c<em>i</em>llum dolore eu fug<em>i</em>at nulla par<em>i</em>atur. Excepteur s<em>i</em>nt occaecat cup<em>i</em>datat non pro<em>i</em>dent, sunt <em>i</em>n culpa qu<em>i</em> off<em>i</em>c<em>i</em>a deserunt moll<em>i</em>t an<em>i</em>m <em>i</em>d est laborum."
}
},
{
title: "Hi",
body: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit",
_highlightResults: {
body: "Sed ut persp<em>i</em>c<em>i</em>at<em>i</em>s unde omn<em>i</em>s <em>i</em>ste natus error s<em>i</em>t voluptatem accusant<em>i</em>um doloremque laudant<em>i</em>um, totam rem aper<em>i</em>am, eaque <em>i</em>psa quae ab <em>i</em>llo <em>i</em>nventore ver<em>i</em>tat<em>i</em>s et quas<em>i</em> arch<em>i</em>tecto beatae v<em>i</em>tae d<em>i</em>cta sunt expl<em>i</em>cabo. Nemo en<em>i</em>m <em>i</em>psam voluptatem qu<em>i</em>a voluptas s<em>i</em>t aspernatur aut od<em>i</em>t aut fug<em>i</em>t, sed qu<em>i</em>a consequuntur magn<em>i</em> dolores eos qu<em>i</em> rat<em>i</em>one voluptatem sequ<em>i</em> nesc<em>i</em>unt. Neque porro qu<em>i</em>squam est, qu<em>i</em> dolorem <em>i</em>psum qu<em>i</em>a dolor s<em>i</em>t amet, consectetur, ad<em>i</em>p<em>i</em>sc<em>i</em> vel<em>i</em>t"
}
]
But what I want it to return, is the following:
[
{
title: "Hello",
_highlightResults: {
body: "Lorem <em>i</em>psum dolor sit amet" // only the first occurance with some context
}
},
{
title: "Hi",
_highlightResults: {
body: "Sed ut persp<em>i</em>ciatis unde" // only the first occurance with some context
}
}
]
I know something similar to this can be done using the snippets, but if you pay close attention, the body field is also removed from the hit body itself so the complete body is never sent to the client. The client can search through the premium contents while the content itself remains unexposed.
How can I achieve this using the Algolia API?
You should be able to implement such logic with snippet. You don't have to return the field to search for it. The snippet feature can control how much context is sent back with the match. You can set the limit to return only a few words to restrict the match to a single occurrence. It won't be 100% accurate though, two matches may be returned if they are closer than the given limit (which shouldn't be a problem for a real use case).
The below example only returns the name
attribute for the search. The description
is set in the searchableAttributes
. It means that the query will use this attribute for the search. It also mean that we can use it with the snippet feature. Here the snippet is restricted to 10 words.
index.search('apple', {
attributesToRetrieve: ['name'],
attributesToSnippet: ['description:10'],
});
Note that those values are set at search time. For a client-side implementation, it means that a user will be able to alter those values. Your use case is about premium content so it's problematic. To work around the problem you have to use an API Key with those parameters burn in it. You won't be able to override them at search time.