Copied to clipboard

Flag this post as spam?

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


  • Kieron 81 posts 246 karma points
    1 week ago
    Kieron
    0

    Need help improving this selection and showing all of 'authors' items

    Hi guys bit of a code dump but looking for a way to improve the below;

    Currently, I take all the news stories on the site, then if the author of the item matches the current page's author (his bio page) I show the articles, ideally you'd have this filter on the selection I think, rather than grabbing all data and then filtering through with an IF.

       @inherits Umbraco.Web.Mvc.UmbracoTemplatePage<ContentModels.NewsAuthors>
    @using ContentModels = Umbraco.Web.PublishedContentModels;
    @using Newtonsoft.Json
    @using Newtonsoft.Json.Linq
    @using nuPickers;
    
    @{
        Layout = "Master.cshtml";
        var prettyAuthorName = @CurrentPage.authorName.Split(' ')[0];
    }
    
    <div class="col-sm-9 leftcolumn">
    @Html.Partial("Mobile Search & Subscribe")
      <section class="maincontent">
        <article class="newsarticle">
          @Html.Partial("Breadcrumbs")
          <h1>@CurrentPage.authorName</h1>
          <div class="col-md-3 no-gutter">
              @{
                IPublishedContent authorPic = CurrentPage.GetPropertyValue<IPublishedContent>("picture");
                }
            <div class="authorimage"><img class="img-responsive" src="@authorPic.GetCropUrl("User Profile")" alt=""></div>
          </div>
          <div class="col-md-9 no-gutter">
            <p>@CurrentPage.authorBio</p>
            <p class="contactbutton"><a href="mailto:@CurrentPage.authorEmail">Contact @prettyAuthorName</a></p>
          </div>
          <div class="clearfix">&nbsp;</div>
    @{
        var selection = Model.Content.Site().Descendants("newsStory").Where(x => x.IsVisible() && x.HasProperty("publishedDate") && x.GetPropertyValue<DateTime>("publishedDate") <= DateTime.Now).OrderBy("publishedDate desc");
    } 
    <h4>Recent Articles by @prettyAuthorName</h4>
    
    <div>
    <div>
    
    
    @foreach(var item in selection){
        Picker test = item.GetPropertyValue<Picker>("author");
            if(CurrentPage.Id.ToString() == test.PickedKeys.First()) {
            <article class="feature mbt clearfix" style="margin-bottom: 5px!important;">
                <div class="inner">
                    <h3>
                        <a href="@item.Url">
                            @item.Name 
                        </a> 
                    </h3>
                    <div class="meta mb" style="padding-top: 3px;">
                        @Umbraco.GetDictionaryValue("doctype_" + item.DocumentTypeAlias) / <span data-momentify="@(item.GetPropertyValue<DateTime>("publishedDate").ToString("yyyyMMddThhmm"))"></span>
    
                    </div>
                    <p class="xsltsearch_result_description">
                        <span class="xsltsearch_description">
                         @item.GetPropertyValue("preview")
                        </span>
                    </p>
                </div>
            </article>
            }
        }
            </div>
          </div>
        </article>
      </section>
    </div>
    

    Part two of this, is that I dont just want news storys, but say items of type newsStory feature blogpost etc what belong to the author, assuming they all have 2 fields in common like title and preview

    Thanks guys

  • Nik 850 posts 3383 karma points MVP c-trib
    1 week ago
    Nik
    100

    Hey Kieron,

    Okay, so if I was doing something like this, what I would do is create my own Examine index. Call it something like "AuthoredDocumentsIndex". In this index I'd store anything you might be after when searching for these. For example, do all of these Authored documents have article dates as you might want to sort on this.

    You can then use Examine to search for all documents where the author = your author.

    This would be better than using Site().Descendent, as this will search every single page in your website that is beneath the root. It can, particularly on large websites, become a bottleneck and it is advised to not use Descendent if you can avoid it.

    Once you've done your Examine search (which can also order on your date field, and potentially do paging as well), you can then get the typed documents from the Umbraco Cache and render out unique previews for each different doc type if you want to :-)

    Thanks,

    Nik

  • Kieron 81 posts 246 karma points
    1 week ago
    Kieron
    0

    This sounded like a good idea so I have attempted, but I'm coming up with an error, here is my code if you wouldn't mind helping out :)

    ExamineSettings:

    <Examine>
      <ExamineIndexProviders>
        <providers>
          <add name="InternalIndexer" type="UmbracoExamine.UmbracoContentIndexer, UmbracoExamine" supportUnpublished="true" supportProtected="true" analyzer="Lucene.Net.Analysis.WhitespaceAnalyzer, Lucene.Net" />
          <add name="InternalMemberIndexer" type="UmbracoExamine.UmbracoMemberIndexer, UmbracoExamine" supportUnpublished="true" supportProtected="true" analyzer="Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net" />
          <!-- default external indexer, which excludes protected and unpublished pages-->
          <add name="ExternalIndexer" type="UmbracoExamine.UmbracoContentIndexer, UmbracoExamine" />
          <add name="AuthorsIndexer" type="UmbracoExamine.UmbracoContentIndexer, UmbracoExamine"
             supportUnpublished="false"
             supportProtected="true"
             analyzer="Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net" indexSet="AuthoredDocumentsIndex"/>
        </providers>
      </ExamineIndexProviders>
      <ExamineSearchProviders defaultProvider="ExternalSearcher">
        <providers>
          <add name="InternalSearcher" type="UmbracoExamine.UmbracoExamineSearcher, UmbracoExamine" analyzer="Lucene.Net.Analysis.WhitespaceAnalyzer, Lucene.Net" />
          <add name="ExternalSearcher" type="UmbracoExamine.UmbracoExamineSearcher, UmbracoExamine" />
          <add name="InternalMemberSearcher" type="UmbracoExamine.UmbracoExamineSearcher, UmbracoExamine" analyzer="Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net" enableLeadingWildcard="true" />
          <add name="AuthorsSearcher" type="UmbracoExamine.UmbracoExamineSearcher, UmbracoExamine"
              analyzer="Lucene.Net.Analysis.WhitespaceAnalyzer, Lucene.Net" indexSet="AuthoredDocumentsIndex" />
        </providers>
      </ExamineSearchProviders>
    </Examine>
    

    ExamineIndex:

    <IndexSet SetName="AuthoredDocumentsIndex" IndexPath="~/App_Data/TEMP/ExamineIndexes/Authors/" IndexParentId="1">
        <IndexAttributeFields>
          <add Name="id" />
          <add Name="nodeName"/>
          <add Name="publishedDate" />
          <add Name="authorName" />
          <add Name="nodeTypeAlias" />
        </IndexAttributeFields>
        <IndexUserFields>
          <!-- Page -->
          <add Name="title" />
          <add Name="preview" />
        </IndexUserFields>
        <IncludeNodeTypes>
          <add Name="newsStory"/>
          <add Name="feature"/>
        </IncludeNodeTypes>
        <ExcludeNodeTypes>
        </ExcludeNodeTypes>
      </IndexSet>
    

    On page in Umbraco:

       @{  
    
            var searchTerm = "germany";
            var searcher = ExamineManager.Instance.SearchProviderCollection["AuthorsSearcher"];
    
            if (searcher == null)
                return null;
    
            var searchCriteria = searcher.CreateSearchCriteria(BooleanOperation.Or);
    
            ISearchCriteria query = searchCriteria.RawQuery(searchTerm);
            IOrderedEnumerable<SearchResult> searchResults = searcher.Search(query).OrderByDescending(x => x.Score);
    
            return searchResults;
    
            }
    

    Thanks in advance, this is new to me so im probably way off!

    edit; error;

    Server Error in '/' Application.
    Parser Error
    Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately. 
    
    Parser Error Message: Expected a "{" but found a "return".  Block statements must be enclosed in "{" and "}".  You cannot use single-statement control-flow statements in CSHTML pages. For example, the following is not allowed:
    
    @if(isLoggedIn)
       <p>Hello, @user</p>
    
    Instead, wrap the contents of the block in "{}":
    
    @if(isLoggedIn) {
       <p>Hello, @user</p>
    }
    
    
    Source Error: 
    
    
    Line 76: 
    Line 77:         if (searcher == null)
    Line 78:             return null;
    Line 79: 
    Line 80:         var searchCriteria = searcher.CreateSearchCriteria(BooleanOperation.Or);
    
    Source File: /Views/Author.cshtml    Line: 78 
    
  • Nik 850 posts 3383 karma points MVP c-trib
    1 week ago
    Nik
    0

    Yep, you can't use a Return statement in your normal Razor code, so return searchResults is causing your error.

    Replace return searchResults with:

    foreach(var searchResult in searchResults.Select(s=> Umbraco.TypedContent(s.Id)))
    { 
        <div>@searchResult.Name</div>
    }
    

    And see if you get a list of document names showing.

  • Kieron 81 posts 246 karma points
    1 week ago
    Kieron
    0

    I did just reply Nik but its vanished, so apologies if this appears twice! I still get the error of:

    Server Error in '/' Application.
    Parser Error
    Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately. 
    
    Parser Error Message: Expected a "{" but found a "return".  Block statements must be enclosed in "{" and "}".  You cannot use single-statement control-flow statements in CSHTML pages. For example, the following is not allowed:
    
    @if(isLoggedIn)
       <p>Hello, @user</p>
    
    Instead, wrap the contents of the block in "{}":
    
    @if(isLoggedIn) {
       <p>Hello, @user</p>
    }
    
    
    Source Error: 
    
    
    Line 76: 
    Line 77:         if (searcher == null)
    Line 78:             return null;
    Line 79: 
    Line 80:         var searchCriteria = searcher.CreateSearchCriteria(BooleanOperation.Or);
    
    Source File: /Views/Author.cshtml    Line: 78 
    

    full block is:

    @{  
    
            var searchTerm = "germany";
            var searcher = ExamineManager.Instance.SearchProviderCollection["AuthorsSearcher"];
    
            if (searcher == null)
                return null;
    
            var searchCriteria = searcher.CreateSearchCriteria(BooleanOperation.Or);
    
            ISearchCriteria query = searchCriteria.RawQuery(searchTerm);
            IOrderedEnumerable<SearchResult> searchResults = searcher.Search(query).OrderByDescending(x => x.Score);
    
                foreach(var searchResult in searchResults.Select(s=> Umbraco.TypedContent(s.Id)))
                { 
                    <div>@searchResult.Name</div>
                }        
            }
    
  • Nik 850 posts 3383 karma points MVP c-trib
    1 week ago
    Nik
    1

    Hey Kieron,

    Just to let you know, your response (at least for me) isn't showing.

    But the e-mail notification I got let me see you still have another return statement in there:

    return null;

    You need to remove this.

    Also in Razor, all if statements have to have { } with them. so you can't do

    if(searcher == null)
         return null;
    

    The reason your reply disappeared I think is a bug. I'm guessing you had this thread open and it automatically loaded my response and you replied to that. If that's the case, don't reply directly to an automatically loaded reply, refresh the page first :-)

  • Kieron 81 posts 246 karma points
    1 week ago
    Kieron
    0

    Thanks buddy ill refresh going forward :D

    New error, haha.

    Server Error in '/' Application.
    Compilation Error
    Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately. 
    
    Compiler Error Message: CS0103: The name 'BooleanOperation' does not exist in the current context
    
    Source Error:
    
    
    Line 77:        
    Line 78: 
    Line 79:         var searchCriteria = searcher.CreateSearchCriteria(BooleanOperation.Or);
    Line 80:         
    Line 81:         ISearchCriteria query = searchCriteria.RawQuery(searchTerm);
    

    This is the guide i followed; http://www.jondjones.com/learn-umbraco-cms/umbraco-developers-guide/umbraco-search/how-to-set-up-a-custom-lucene-index-with-umbraco

    Thanks for your help!

    Edit; adding @using Examine.SearchCriteria; fixed it, but no results, so maybe i need to adjust my search query.

    I get no results though, which i guess could mean the search is working but maybe im pointing to the wrong place, I did guess quite heavily on the ExamineIndex and ExamineSettings.

  • Nik 850 posts 3383 karma points MVP c-trib
    1 week ago
    Nik
    1

    okay.. so first thing I'd do to check is use the Examine section in the Developer part of the back office.

    I'd find the new index in there and check that if you search using the term you are searching for you get results back.

    If you get results with that term, you know that your index is populated with values :-)

  • Kieron 81 posts 246 karma points
    1 week ago
    Kieron
    0

    Thanks this is great insight.

    Documents in index is currently 0, which is probably why its not giving me any back.

    Include node types  [ "newsStory", "feature" ]
    Parent node id  1
    

    I wonder if these are affecting it, these items are nested probably 3 levels down. Any ideas? :)

  • Nik 850 posts 3383 karma points MVP c-trib
    1 week ago
    Nik
    1

    I'd remove IndexParentId="1" from your index configuration, then in the back office I'd tell it to rebuild the index.

  • Kieron 81 posts 246 karma points
    1 week ago
    Kieron
    0

    Great, it's going quite well, I've got results now outputting, so Umbraco is currently:

      @{  
            var authID = Model.Content.Id.ToString();
            var searchTerm = authID;
            var searcher = ExamineManager.Instance.SearchProviderCollection["AuthorsSearcher"];
            var searchCriteria = searcher.CreateSearchCriteria(BooleanOperation.Or);
    
            ISearchCriteria query = searchCriteria.RawQuery(searchTerm);
            IOrderedEnumerable<SearchResult> searchResults = searcher.Search(query).OrderByDescending(x => x.Score);
    
                foreach(var searchResult in searchResults.Select(s=> Umbraco.TypedContent(s.Id)))
                { 
                    <a href="@searchResult.Url">@searchResult.GetPropertyValue("title")</a>
                }   
        }
    

    Then to only search for the matching author's items, I actually removed the rest of the data types from the ExamineIndex.config, like so;

     <IndexSet SetName="AuthoredDocumentsIndex" IndexPath="~/App_Data/TEMP/ExamineIndexes/Authors/">
         <IndexAttributeFields>
          <add Name="id" />
          <!-- <add Name="nodeName"/> -->
          <!-- <add Name="updateDate" /> -->
          <!-- <add Name="writerName" /> -->
          <!-- <add Name="nodeTypeAlias" /> -->
        </IndexAttributeFields>
        <IndexUserFields>
          <!-- Page -->
          <!-- <add Name="title" /> -->   
          <!-- <add Name="preview" /> -->   
          <!-- <add Name="publishedDate" /> -->      
    

    Because the item of 'author' comes out as author: [{"key":"1256","label":"Dudes Name"}] so by searching current authors id of 1256 against that item, it matches. I guess I wasn't sure if I should tell it where to look, or simply remove the things I don't want it to look at. If that makes sense!

    So that works, is that all good practice in your eyes?

    Thanks a bunch

  • Nik 850 posts 3383 karma points MVP c-trib
    1 week ago
    Nik
    1

    Personally, I would have the fields I need included in the index, so I'd have the Author, the date you want to search on, the title, the ID, and the nodeTypeAlias.

    In case you wanted to extend your searching at any point.

    I'd then do my query specifically on the field I want to search against.

    Whether this is best practice or not I don't know.

  • Kieron 81 posts 246 karma points
    1 week ago
    Kieron
    0

    That's cool, do you have any insight or recommended reading on applying the query to a specific field?

    I have one last question, how might I order by? I tried editing

    IOrderedEnumerable<SearchResult> searchResults = searcher.Search(query).OrderByDescending(x => x.Score); to be something like;

    IOrderedEnumerable<SearchResult> searchResults = searcher.Search(query).OrderBy("publishedDate desc"); or .OrderBy("x.publishedDate"); But not having much luck with either!

    Thanks very much for your help.

  • Nik 850 posts 3383 karma points MVP c-trib
    1 week ago
    Nik
    1

    Okay, regarding sorting:

    Change your entry in your index for the date field to:

    <add Name="publishedDate" EnableSorting="true" Type="DateTime" />
    

    Without the additional attributes the field won't be sortable by default, and it also won't know how to treat the data in there so will treat it as a string.

    Regarding searching a specific field and sorting at the point of query.

    var searchCriteria = searchProvider.CreateSearchCriteria(IndexTypes.Content);
    var query = searchCriteria.Field("fieldName", searchTerm).And().OrderByDescending("articleDate");
    

    Then you perform the search by doing:

    searchProvider.Search(query.Compile())
    
  • Kieron 81 posts 246 karma points
    1 week ago
    Kieron
    0

    Ok, thank you, sorry I know this has taken a while but I am struggling to merge the new code in, I have this;

      var searchTerm = Model.Content.Id.ToString();
            var searcher = ExamineManager.Instance.SearchProviderCollection["AuthorsSearcher"];
            var searchCriteria = searcher.CreateSearchCriteria(IndexTypes.Content);
    
            ISearchCriteria query = searchCriteria.RawQuery(searchTerm);
            IOrderedEnumerable<SearchResult> searchResults = searcher.Search(query).OrderByDescending("publishedDate");
    
                foreach(var item in searchResults.Select(s=> Umbraco.TypedContent(s.Id)))
                { 
    
                }
    

    But i am getting:

    The name 'IndexTypes' does not exist in the current context

    I have avoided the field targeting because I was a bit overwhelmed, lol.

    Thank you

  • Nik 850 posts 3383 karma points MVP c-trib
    1 week ago
    Nik
    1

    You are missing this namespace :-)

    using UmbracoExamine;
    

    That will give you access to the IndexTypes enum

  • Kieron 81 posts 246 karma points
    1 week ago
    Kieron
    0

    That was it, however...

    The type arguments for method 'System.Linq.Enumerable.OrderByDescending<TSource,TKey>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,TKey>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

    Sorry!

    If I can just order by then this project is finished, haha. were close I'm sure :D

    From some googling I think im still dealing with a string not a date object?

    Ive just confirmed this in the back end; Name: publishedDate, Enable Sorting: true, Type:DateTime

    Any ideas?

  • Nik 850 posts 3383 karma points MVP c-trib
    1 week ago
    Nik
    1

    Hi Kieron,

    Yep, I think it's because the way you are trying to do the ordering isn't using Examine it's using Linq.

    To achieve ordering the way you are going about it I think you'll need to do something like

    IOrderedEnumerable<SearchResult> searchResults = searcher.Search(query).OrderByDescending(r => r.Field["publishedDate"]);
    

    (I've not tested this and off the top of my head I can't remember how you access a field on a search result but I think that is about right.

    Thanks

    Nik

  • Kieron 81 posts 246 karma points
    1 week ago
    Kieron
    0

    Thats perfect (except for one letter*) Nik thanks so much for your help and patience :D

    *PS, Field needs to be Fields

    Thanks again

  • Nik 850 posts 3383 karma points MVP c-trib
    1 week ago
    Nik
    1

    No worries at all :-) Happy to help.

Please Sign in or register to post replies

Write your reply to:

Draft