Copied to clipboard

Flag this post as spam?

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


  • Chris Houston 535 posts 980 karma points MVP admin c-trib
    Apr 07, 2016 @ 14:09
    Chris Houston
    0

    Returning a list of IContent items with a grand child item containing a known property.

    Hi All,

    I am trying to get my head around how to return an IEnumerable list of IContent items ( e.g. both published and un-published items ) where one of the grand child items has a known property.

    E.g.

    If we have the following structure:

    Building > Floor > Room

    And the Room node has a property called " Number of Chairs "

    I want to get a list of all Building's where the is at least one Room with 5 chairs.

    As mentioned above this needs to be both Published and Un-published items, hence I cannot do an XPATH query on the published nodes.

    Cheers, Chris

  • Bo Damgaard Mortensen 719 posts 1207 karma points
    Apr 07, 2016 @ 14:39
    Bo Damgaard Mortensen
    0

    Hiya Chris,

    I think you should be able to do this with the IContentService. The IContentService has methods like GetDescendants(int nodeId) with an overload, which takes an IContent. This gets the descendant IContents of a current IContent.

    So, bascially:

    var contentService = ApplicationContext.Services.ContentService;
    var rootContent = contentService.GetById(1234) // should not be hardcoded, this is just for having a starting point.
    var rooms = contentService.GetDescendants(rootContent).Where(x => x.ContentType.Alias.Equals("room") && HasProperty("numberOfChairs) && x.GetValue<int>("numberOfChairs") > 5);
    

    Things to note about this:

    1. the GetDescendants() call can be slow if there's a lot of child (and sub-child) nodes in the tree.
    2. using the IContentService performs database calls, afaik (correct me if I'm wrong here) which also is not very performant. However, it's needed to get the unpublished nodes aswell.

    An alternative is the method GetContentOfContentType(int id) method on the IContentService, but this should only ever be used if you are certain you want all nodes of a given type. I.e., this might not be the case when running multilingual sites.

    Hope this helps any :-)

    All the best,

    Bo

  • Michaël Vanbrabandt 863 posts 3348 karma points c-trib
    Apr 07, 2016 @ 14:39
    Michaƫl Vanbrabandt
    0

    Hi Chris,

    You could do something like:

    var _buildingNode = Umbraco.TypedContentAtRoot().DescendantsOrSelf("buildDocumentTypeAlias").FirstOrDefault();
    var _rooms = _buildingNode.Descendants("roomsDocumentType").Where(a => int.Parse(a.GetPropertyValue("numberOfChairs")) > 5);
    

    /Michael

  • Jamie Howarth 306 posts 773 karma points c-trib
    Apr 07, 2016 @ 14:42
    Jamie Howarth
    0

    TypedContent returns an IPublishedContent, which only works for published nodes, Chris said he needs published and unpublished, so this won't work for his scenario.

  • Jamie Howarth 306 posts 773 karma points c-trib
    Apr 07, 2016 @ 14:40
    Jamie Howarth
    1

    Caveat emptor: this will be DB-heavy, but should do the trick.

    var roomType = ApplicationContext.Current.Services.ContentTypeService.GetContentType("Room");
            var allRoomsWithFiveChairs = ApplicationContext.Current.Services.ContentService.GetContentOfContentType(roomType.Id)
                .Where(p => p.HasProperty("NumberOfChairs") && p.GetValue<int>("NumberOfChairs") > 5);
    
            var buildings =
                allRoomsWithFiveChairs.Select(p => p.Ancestors().Single(b => b.ContentType.Alias == "Building"));
    
  • Ben McKean 272 posts 549 karma points
    Apr 07, 2016 @ 14:41
    Ben McKean
    1

    Hi Chris,

    I presume it needs to be the structure that you said because there are pages for each of Building > Floor > Room ?

    My answer if not would be to store all the data on the Building node but I guess you're stuck with that structure.

    If not, how about using Examine to search the Room nodes and then when you have the result display the Parent.Parent or if thats not possible with IContent (not done much with it sorry) you could query the path put that into a comma separated array and go 2 levels up.

    Sorry if I've misunderstood any of your requirement!

    Ben

  • Chris Houston 535 posts 980 karma points MVP admin c-trib
    Apr 07, 2016 @ 14:47
    Chris Houston
    0

    Hi All,

    I think you must all be thirsty, I mentioned beer on twitter and this thread just lit up :-)

    Thank you all for your replies, really appreciated.

    I think Benjamin Howarth has quite possibly hit the nail on the head, I will give it a go and get back to the thread shortly.

    Cheers, Chris

  • Jules 276 posts 587 karma points
    Apr 07, 2016 @ 15:29
    Jules
    100
    IContent node = Umbraco.Content(345); // this the parent node of Building
    
    var result = node.Children().Where(x => x.ContentType.Alias == "Building" && x.Descendants().FirstOrDefault(y => y.ContentType.Alias == "Room" && y.HasProperty("noOfChairs") && y.GetValue<int>("noOfChairs")==5) != null);
    

    Possibly not that performant with lots of nodes

  • Richard Terris 273 posts 715 karma points
    Apr 07, 2016 @ 16:07
    Richard Terris
    0

    You didn't say 'correctly answering' so can I just get a beer?

  • Jules 276 posts 587 karma points
    Apr 08, 2016 @ 07:06
    Jules
    1

    Just edited my answer above to filter out the doc types. I fully admit that Ben Howarth's answer is more readable and I really like the way he thought about it the other way round but my answer'll work just as well :)

    J

  • Chris Houston 535 posts 980 karma points MVP admin c-trib
    Apr 14, 2016 @ 14:34
    Chris Houston
    0

    Hi All,

    Thank you all for your replies, in the end I actually ended up using Jule's solution hence I marked it as the solution, however I think Ben Howarth also provided a good solution as well.

    I have not had the chance to test if one out performs the other, maybe if I ever get some spare time I will test it.

    Thanks again for all your quick responses and for Richard Terris... you can have a half ;-)

    Cheers,

    Chris

Please Sign in or register to post replies

Write your reply to:

Draft