Copied to clipboard

Flag this post as spam?

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


  • Simone Chiaretta 134 posts 541 karma points c-trib
    Feb 15, 2016 @ 11:17
    Simone Chiaretta
    0

    How to filter nodes based on content of property whose type is MultiNodeTreePicker

    I've a list of nodes which contain a property (called "topics") which is a MultiNodeTreePicker.

    In a page I've to list all the nodes about a specific topic, so what I should do it search for all nodes that have a specific id in the topics field.

    At the moment I'm doing:

    .Where(x =>
    x.ContentType.Alias == "Meeting" && 
    x.GetPropertyValue<String>("topics").Split(',').ToList().Contains(Model.Content.Id.ToString()));
    

    But this kind of ugly and not sure about performances.

    Is there a better way of doing this?

    Simone

  • Dan Diplo 1554 posts 6205 karma points MVP 5x c-trib
    Feb 15, 2016 @ 12:50
    Dan Diplo
    101

    If you install the Core Property converters package - https://our.umbraco.org/projects/developer-tools/umbraco-core-property-value-converters/ - then you should be able to do:

    .Where(x => x.ContentType.Alias == "Meeting" && x.GetPropertyValue<IEnumerable<IPublishedContent>>("topics")
    .Select(p => p.Id).
    Contains(Model.Content.Id));
    

    I think this reads a bit better, but would guess it might perform slightly worse.

    I often use a static helper method something like:

    /// <summary>
    /// Converts a delimitted string to an enumarable of integers
    /// </summary>
    /// <param name="csvString">The CSV string</param>
    /// <param name="separator">The delimiter character</param>
    /// <param name="addDefaultOnFail">Set to true to add the default value for type T if the conversion fails</param>
    /// <returns>A list of integers</returns>
    public static IEnumerable<int> ToIntCsvList(string csvString, char separator = ',', bool addDefaultOnFail = false)
    {
        if (String.IsNullOrEmpty(csvString))
            yield break;
    
        var values = csvString.Split(separator);
        int d;
    
        foreach (var item in values)
        {
            if (int.TryParse(item, out d))
            {
                yield return d;
            }
            else if (addDefaultOnFail)
            {
                yield return default(int);
            }
        }
    
        yield break;
    }
    

    You can then call it like this:

    .Where(x => x.ContentType.Alias == "Meeting" &&
    StringHelper.ToIntCsvList(x.GetProperty("topics").DataValue.ToString()).Contains(Model.Content.Id));
    

    Again, not sure if it's more readable, but should be efficient and more resilient.

  • Simone Chiaretta 134 posts 541 karma points c-trib
    Feb 15, 2016 @ 13:17
    Simone Chiaretta
    0

    Thx. I guess I'll go with the helper as I don't need the actual node but just need to filter them based on Id :)

    Hopefully the new Model Builder will handle this

  • Damiaan 442 posts 1301 karma points MVP 6x c-trib
    Feb 15, 2016 @ 14:01
    Damiaan
    0

    What the Property value converters do is calling a UmbracoHelper.TypedContent(myIEnumerableOfIds). This will use the cache and is pretty quick.

  • Simone Chiaretta 134 posts 541 karma points c-trib
    Feb 15, 2016 @ 14:10
    Simone Chiaretta
    0

    Which Property Value converter?

  • Damiaan 442 posts 1301 karma points MVP 6x c-trib
    Feb 15, 2016 @ 15:42
    Damiaan
    1

    the MultiNodeTreePickerPropertyConverter

    this is the source or the Core Property Converter package.

  • Sérgio 30 posts 171 karma points
    Aug 09, 2018 @ 10:25
    Sérgio
    0

    Here's my take at it using 7.11.1:

    posts = Umbraco.TypedContent(rootNodeId)
                            .Children()
                            .OfTypes("article")
                            .Where(x => x.GetPropertyValue<List<IPublishedContent>>("otherCategories").Any(c => c.Id == categoryNode.Id))
                            .OrderByDescending(x => x.GetPropertyValue<DateTime>("publishedDate"));
    

    Some explanation:

    • roteNodeId is my homepage Id. This is a "blog" kind of website so I want to get all posts of the type "article", no matter where they are;
    • otherCategories is the property (MultiNodeTreePicker) in which I indicate the other categories the posts belong to;
    • categoryNode is the node for the category I want the articles from. For example: News or Previews;

    This is working great for me. I hope it helps you.

  • Dan Diplo 1554 posts 6205 karma points MVP 5x c-trib
    Aug 09, 2018 @ 12:16
    Dan Diplo
    0

    Just be aware that calling Descendants() of the root node can have horrible performance issues on sites with a lot of nodes, as it has to iterate over every single node.

    It's one of the anti-patterns outlined here:

    https://our.umbraco.com/documentation/Reference/Common-Pitfalls/#querying-with-descendants-descendantsorself

    You'll get away with it on smaller sites, especially if you cache results in a partial, but beware. If all your articles are stored under one parent node it's better to start at the parent node and just get the children.

  • Sérgio 30 posts 171 karma points
    Aug 09, 2018 @ 12:27
    Sérgio
    0

    Indeed. You are right.

    I am using Descendants() on a very specific task. It should be replaced with Children(). I will update accordingly.

Please Sign in or register to post replies

Write your reply to:

Draft