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 23 posts 112 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 713 posts 4571 karma points MVP 6x 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 23 posts 112 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 713 posts 4571 karma points MVP 6x 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 510 posts 2082 karma points
    Jan 11, 2020 @ 14:41
    David Armitage
    1

    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 510 posts 2082 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>
    }
    
  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies