Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Giant Penguin 13 posts 82 karma points
    Sep 12, 2019 @ 11:00
    Giant Penguin
    0

    How can paginate with Umbraco 8 Examine

    I could not find out any overload of ISearcher.Search or IQueryExecutor.Execute that support returning paging.

    Any idea about the search result's pagination with Umbraco 8?

    Note that this is a custom search - I want to search on some specific document types.

  • Søren Kottal 452 posts 2863 karma points MVP c-trib
    Sep 12, 2019 @ 12:14
    Søren Kottal
    1

    Hi there :)

    Check out this article: https://shazwazza.com/post/paging-with-examine/

    Basically you need to set maxResults to the number of results per page (multiplied by the current pagenumber), and then skip through the ones you have already shown.

    //for example purposes, we want to show page #4 (which is pageIndex of 3)
    var pageIndex = 3;   
    //for this example, the page size is 10 items
    var pageSize = 10;
    var searchResult = searchProvider.Search(criteria, 
       //don't return more results than we need for the paging
       //this is the 'trick' - we need to load enough search results to fill
       //all pages from 1 to the current page of 4
       maxResults: pageSize*(pageIndex + 1));
    //then we use the Skip method to tell Lucene to not allocate search results
    //for the first 3 pages
    var pagedResults = searchResult.Skip(pageIndex*pageSize);
    var totalResults = searchResult.TotalItemCount;
    
  • Giant Penguin 13 posts 82 karma points
    Sep 23, 2019 @ 09:59
    Giant Penguin
    0

    Thank Søren Kottal!

    How ISearchResult can be casting to IPublishedContent for rendering in view? I could not see ISearchResult has its structure for easy rendering.

  • Søren Kottal 452 posts 2863 karma points MVP c-trib
    Sep 23, 2019 @ 10:12
    Søren Kottal
    0

    Hi again

    var pagedResultsAsContent = Umbraco.Content(pagedResults.Select(x => x.Id));

    Gives you a list of IPublishedContent from the ids in your ISearchResult

  • David Armitage 243 posts 920 karma points
    Jan 11, 2020 @ 14:41
    David Armitage
    0

    Here is a complete solution. Hope it helps someone.

    This is the way I like to handle this.

    I create a model called BlogSearch. This will contain the search fields, the paging information, and the blog article results

    using System.Collections.Generic;
    
    namespace Website.Core.Models.EntityModels
    {
        public class BlogSearch
        {
            public string Tag { get; set; }
            public string Keywords { get; set; }
    
    
            //return fields
            public List<BlogDetailsPage> Articles { get; set; }
            public int CurrentPage { get; set; }
            public int TotalPages { get; set; }
            public int TotalItems { get; set; }
            public int ItemsPerPage { get; set; }
    
            public BlogSearch()
            {
                CurrentPage = 1;
            }
        }
    
    }
    

    I then have an Umbraco helper / service / component. Whatever you want to call it. This performs the search login and handles the paging.

    using System;
    using Umbraco.Core;
    using Umbraco.Examine;
    using Examine;
    using Umbraco.Web;
    using Website.Core.Models.EntityModels;
    using Examine.Search;
    using System.Linq;
    using System.Collections.Generic;
    using Website.Core.Models;
    using Umbraco.Web.PublishedCache;
    
    namespace Website.Core.Helpers
    {
        public interface IBlogHelper
        {
            BlogSearch Search(BlogSearch blogSearch);
        }
    
        public class BlogHelper : IBlogHelper
        {
            private readonly IUmbracoContextFactory _umbracoContextFactory;
            private readonly IExamineManager _examineManager;
    
            public BlogHelper(IUmbracoContextFactory umbracoContextFactory, IExamineManager examineManager)
            {
                _umbracoContextFactory = umbracoContextFactory;
                _examineManager = examineManager;
            }
    
            public BlogSearch Search(BlogSearch blogSearch)
            {
                IExamineManager examineManager = ExamineManager.Instance;
    
                if (!examineManager.TryGetIndex(Constants.UmbracoIndexes.ExternalIndexName, out IIndex index))
                    throw new InvalidOperationException($"No index found by name {Constants.UmbracoIndexes.ExternalIndexName}");
    
                var searcher = index.GetSearcher();
                var criteria = searcher.CreateQuery(IndexTypes.Content, BooleanOperation.And);
                var examineQuery = criteria.NodeTypeAlias("blogDetailsPage");
    
                if (!string.IsNullOrEmpty(blogSearch.Tag))
                    examineQuery.And().Field("tags", blogSearch.Tag);
    
                if (!string.IsNullOrEmpty(blogSearch.Keywords))
                {
                    if (blogSearch.Keywords.Contains(" "))
                    {
                        string[] terms = blogSearch.Keywords.Split(' ');
                        examineQuery.And().GroupedOr(new[] { "contents" }, terms);
                    }
                    else
                    {
                        examineQuery.And().Field("contents", blogSearch.Keywords.MultipleCharacterWildcard());
                    }
                }
    
                examineQuery.OrderByDescending(new SortableField[] { new SortableField("sortableDate") });
    
    
                int pageIndex = blogSearch.CurrentPage - 1;
                int pageSize = blogSearch.ItemsPerPage;
                ISearchResults searchResult = examineQuery.Execute(maxResults: pageSize * (pageIndex + 1));
                IEnumerable<ISearchResult> pagedResults = searchResult.Skip(pageIndex * pageSize);
                int totalResults = Convert.ToInt32(searchResult.TotalItemCount);
                blogSearch.TotalItems = totalResults;
                blogSearch.TotalPages = (totalResults + blogSearch.ItemsPerPage - 1) / blogSearch.ItemsPerPage;
    
                if(pagedResults != null && pagedResults.Count() > 0)
                    blogSearch.Articles = GetBlogArticlesFromSearch(pagedResults);
    
                return blogSearch;
            }
    
            private List<BlogDetailsPage> GetBlogArticlesFromSearch(IEnumerable<ISearchResult> pagedResults)
            {
                List<BlogDetailsPage> blogDetailsPages = new List<BlogDetailsPage>();
                using (UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext())
                {
                    foreach (ISearchResult result in pagedResults)
                    {
                        if (int.TryParse(result.Id, out int nodeId))
                        {
                            IPublishedContentCache contentHelper = umbracoContextReference.UmbracoContext.Content;
                            BlogDetailsPage blogDetailsPage = contentHelper.GetById(nodeId) as BlogDetailsPage;
                            if(blogDetailsPage != null)
                            {
                                blogDetailsPages.Add(blogDetailsPage);
                            }
                        }
                    }
                }
    
                return blogDetailsPages;
            }
        }
    }
    

    Here is the composer to go along with the service above.

    using Umbraco.Core;
    using Umbraco.Core.Composing;
    
    namespace Website.Core.Events
    {
        [RuntimeLevel(MinLevel = RuntimeLevel.Run)]
        public class ExamineComposerPublic : IUserComposer
        {
            public void Compose(Composition composition)
            {
                composition.Components().Append<ExamineComponents>();
            }
        }
    }
    

    And finally this is an example of my page controller which calls my BlogHelper service.

    using Website.Core.Models;
    using Website.Core.Helpers;
    using Website.Core.Models.EntityModels;
    using System.Web.Mvc;
    using Umbraco.Web.Models;
    using Umbraco.Web.Mvc;
    
    namespace Website.Core.Controllers
    {
        public class BlogListPageController : RenderMvcController
        {
            private readonly ISiteHelper _siteHelper;
            private readonly IBlogHelper _blogHelper;
    
            public BlogListPageController(ISiteHelper siteHelper, IBlogHelper blogHelper)
            {
                _siteHelper = siteHelper;
                _blogHelper = blogHelper;
            }
    
            [HttpGet]
            public override ActionResult Index(ContentModel model)
            {
                string tag = string.IsNullOrEmpty(Request["tag"]) ? string.Empty : Request["tag"];
                string keywords = string.IsNullOrEmpty(Request["keywords"]) ? string.Empty : Request["keywords"];
                string page = string.IsNullOrEmpty(Request["page"]) ? "1" : Request["page"];
    
                if(!int.TryParse(page, out int pageNumber))
                    pageNumber = 1;
    
                var vm = new BlogListPageViewModel(_siteHelper, model.Content) { };
    
                BlogSearch blogSearch = new BlogSearch();
                blogSearch.CurrentPage = pageNumber;
                blogSearch.ItemsPerPage = vm.PageContent.ItemsPerPage;
                blogSearch.Tag = tag;
                blogSearch.Keywords = keywords;
                vm.BlogSearch = _blogHelper.Search(blogSearch);
                return View("/Views/blogListPage.cshtml", vm);
            }
        }
    }
    
  • David Armitage 243 posts 920 karma points
    Jan 11, 2020 @ 14:42
    David Armitage
    0

    And a very simple view would look something like this.

    @inherits UmbracoViewPage<Website.Core.Models.BlogListPageViewModel>
    @using Website.Core.Models
    @{
        Layout = "master.cshtml";
    }
    
    @{
        if (Model.BlogSearch.Articles.Any())
        {
            @RenderResults(Model.BlogSearch.Articles)
        }
        else
        {
            <p> No results found for query</p>
        }
    }
    
    @helper RenderResults(List<BlogDetailsPage> articles)
    {
        <ul>
    
            @foreach (BlogDetailsPage article in articles)
            {
                <li>
                    <a href="@article.Url">@article.Name</a>
                    <br />Date - @(article.Date.ToString("dd MMM yyyy"))
                </li>
            }
        </ul>
    }
    
Please Sign in or register to post replies

Write your reply to:

Draft