Virtual Happy Hour this month, Jun 28, we'll be getting a sneak preview at our soon to launch SaaS CMS!

Try our conversational search powered by Generative AI!

Search across multiple page types

Vote:
 

Hi,

I have two page types:

EventPage

DateAndTime
Location
... page specific properties

and

ExternalEventPage

DateAndTime
Location
... page specific properties

I need to build a search functionality that will get me both EventPage and ExternalEventPage with the following filter:

.Filter(x => x.DateAndTime.After(DateTime.Now));

I also want to avoid calls to EPiServer database by returning PageReference as search hits, and then calling ContentLoader.Get<> in order to fetch the page / properties I need.

In Lucene.NET, I would index DOCUMENT_TYPE and DATE_AND_TIME fields (as well as [age specific properties for each page type), and then simply get the values from a dictionary:

var documentType = luceneDocument.Get("DOCUMENT_TYPE");
if (documentType == "EventPage")
{
    ... = luceneDocument.Get("SOME_FIELD_1")
    ... = luceneDocument.Get("SOME_FIELD_2")
    ...
}
else if (documentType == "ExternalEventPage")
{
   ...
}

How can I accomplish the same task using EPiServer Find?

Thanks!

#139836
Oct 07, 2015 13:35
Vote:
 

Look at either Multisearch

http://world.episerver.com/documentation/Items/Developers-Guide/EPiServer-Find/9/DotNET-Client-API/Searching/Multiple-searches-in-one-request/

or

search over multiple types

http://world.episerver.com/documentation/Items/Developers-Guide/EPiServer-Find/9/DotNET-Client-API/Searching/Searching-over-multiple-types/

Both of this will only support GetResult so you will not get a page reference. But if I am not wrong if you use getcontentresult to get content EPiServer will do a request to database if it does not have it in cache so if you are looking into performace, you should look into projecting into a type that you can use all the way so you wont need to call the database at all.

#139838
Oct 07, 2015 13:55
Vote:
 

How about something like this:

                var result = SearchClient.Instance.Search<PageData>()
                    .Filter(x => ((EventPage) x).DateAndTime.After(DateTime.Now))
                    .Filter(x => x.MatchType(typeof (EventPage)) | x.MatchType(typeof (ExternalEventPage)))
                    .GetContentResult();

This should return EventPages and ExternalEventPages as PageData, so you'll need to check the results orginal type. Don't worry about the EventPage cast. The filter will work even though ExternalEventPage cannot be casted to EventPage. 


As Henrik mentions, GetContentResult will fetch the page using the content loader. However, you should not be worried about that as the pages will be cached.

#139841
Oct 07, 2015 14:12
Vote:
 

Per Magne, will this line work if not Eventpage is basepage of ExternalEventPage?

.Filter(x => ((EventPage) x).DateAndTime.After(DateTime.Now))

You are correct about caching, it should work ok.

#139842
Oct 07, 2015 14:23
Vote:
 

@Henrik, it will work. When the code is executed, the cast will never actually be done. All that Find care about is the property name, which is "DateAndTime". 

#139843
Oct 07, 2015 14:30
Vote:
 

@Henrik,

I tried http://world.episerver.com/documentation/Items/Developers-Guide/EPiServer-Find/10/DotNET-Client-API/Searching/Searching-over-multiple-types/ but obviously I'm doing something wrong as I`m getting 0 hits:

var searchQuery = SearchClient.Instance.Search<EventViewModel>()
                                .Filter(x => x.DateAndTime.After(DateTime.Now));

// TODO: dynamic filters

searchQuery.IncludeType<EventViewModel, EventPage>(x => new EventViewModel
{

    DateAndTime = x.DateAndTime,
    Location = x.Location,
    // rest of the fields
    IsExternal = false
}).IncludeType<EventViewModel, ExternalEventPage>(x => new EventViewModel
{
    DateAndTime = x.DateAndTime,
    Location = x.Location,
    // rest of the fields
    IsExternal = true
});

var result = searchQuery.OrderBy(x => x.DateAndTime)
                        .Skip((pageNumber - 1) * pageSize)
                        .Take(pageSize)
                        .GetResult();

@Per,

I want to avoid GetContentResult() as I`m using CQRS approach to index data that is optimized for search. I want to prepare data / do calculations only once (on page publishing event), instead of doing it every time on search results page.

#139844
Oct 07, 2015 14:36
Vote:
 

the IncludeType filtering is not being added. You need to assign it to a new variable.

var searchQuery2 = searchQuery.IncludeType<....

#139845
Oct 07, 2015 14:45
Vote:
 

or include it in your original query

#139846
Oct 07, 2015 15:02
Vote:
 

Thank you guys! Works like a charm!

#139849
Oct 07, 2015 15:11
Vote:
 

Thanks Per Magne, I did not know Find worked that way.


Dejan, I have done exactly the same error many times and then trying to found out why it is not working when it all looks good.... Just a little variable = variable...... :)

Glad to help and glad that i works!

#139850
Oct 07, 2015 15:38
Vote:
 

I know this is already marked as answered. Bur if your page types shares the same properties, why not use a base class or interface and then search for that type instead?

#139858
Oct 07, 2015 21:30
Vote:
 

I agree with Johan. Using an interface would be probably make the code a bit cleaner.

#139862
Oct 08, 2015 8:35
Vote:
 

I need to display 4-5 fields from one page type (properties + some pre-calculated data) and 4-5 fields from the other one. Only 2 fields (Location and Date) are common, so I can create an interface for that, but how can I use it to create projections?

I'd like to avoid a call to GetPagesResultGetContentResult.

Thanks for help!

#139872
Oct 08, 2015 10:20
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.