What's the best way to get all content at or below a group using an In-Process Service?

I'm creating an In-Process plugin (INavigable) that provides an endpoint for custom RSS feeds (e.g. content filters specified in URL) for backward compatibility from a similar implementation on another non-Telligent community platform.  The backward compatibility part is key because it's actually integrated with a number of the customer's products.

So, if I had a site structure like this:

  • Products (group)
    • Product Category 1 (group)
      • Product 1-A (group)
        • Discussions 
        • Blog
        • Files (group)
          • Media Gallery 1
          • Media Gallery 2
        • Feature Requests
        • Documents (wiki)

      • Product 1-B (group
      • Product ...
    • Product Category 2 (group)
      • Product 2-A
        • ...
      • Product 2-B
        • ...
      • Product ...

I'm trying to figure out a way to get {numItems} pieces of content from the leaf nodes (applications) given a higher-level group node (e.g. Product Category 1) and order the results by date created in descending order.  I'd also like to be able to further filter content by {tags} or {contentType}. 

Is there an In-Process API service (or perhaps more than one) that can accommodate that?  

Thanks!

  • While there are listing APIs included for all the different included application types, there isn't a generic content listing API, as the content model's extensibility means that content data source can be whatever the content type defines them to be.

    So, while it would be possible to stitch together this kind of data from iterating groups and applications, a better approach might be to just rely on the search index. In fact, the site search feature included in the site banner widget already makes use of the search API to retrieve similar sets of data (group's content, regardless of type, including the group's sub-groups).

    The search API can be a little challenging at times, but one way to make use of it for this purpose may be to see what's passed to its script API via the Site Banner. 

    Hope this helps!

  • That mostly seems to be working.  Just thought I'd share some of the code in case someone else wanted to see an example...

                    var search = Apis.Get<SearchResults>();
                    var searchOptions = new SearchResultsListOptions
                    {
                        PageSize = 100,
                        PageIndex = 0,
                        Sort = "date desc",
                        IsContainer = false,
                        IsApplication = false,
                        IsContent = true,
                        Collapse = true,
                        Filters = "category::file,wiki,idea,forum,blog"
                    };
    
    
                    do
                    {
                        var results = search.List(searchOptions);
                        if (results.Count == 0) break;
    
                        foreach (var result in results)
                        {   
                            // break condition to bail out of for/each
                            if (breakCondition) break;
                        }
                        
                        // break condition to bail out of while loop
                        if (breakCondition) break;
    
                        searchOptions.PageIndex++;
                        if (searchOptions.PageIndex * searchOptions.PageSize >= results.TotalCount) break;
    
                    } while (true);

  • One more caveat to add, search only returns content from subgroups if SearchResultsListOptions.ContainerId is not set, so it only works for the root down.  This was kind of tricky to figure out because the documentation doesn't really spell out the meaning of any of the properties on the various In-Process APIs or their related classes.  Essentially, I had to run SOLR from the command line in verbose mode so I could look at the what the requests looked like when they were coming over and then figure out how to craft the search options until I got a format that was transformed into what SOLR was expecting.

    If you have a group and you want the search result to include content from its subgroups, it appears that you need to add a FieldFilter to the search options.

    Here's an example:

    ...
    
    // Group is a group object I retrieved already
    // IncludeSubGroups and IncludePrivateGroups are boolean flags
    
    var searchOptions = new SearchResultsListOptions
    {
        PageSize = 100,
        PageIndex = 0,
        Sort = "date desc",
        IsContainer = false,
        IsApplication = false,
        IsContent = true,
        Collapse = true,
        Filters = "category::file,wiki,ideas,forum,blog",
    };
    
    var groupList = new HashSet<string> { Group.ContainerId.ToString() };
    
    if (IncludeSubgroups)
    {
        var listOptions = new GroupsListOptions { ParentGroupId = Group.Id, IncludeAllSubGroups = true, PageSize = 100};
        var subGroups = Apis.Get<IGroups>.List(listOptions);
        foreach (var subGroup in subGroups.Where(g => IncludePrivateGroups || g.GroupType == "Joinless"))
        {
            groupList.Add(subGroup.ContainerId.ToString());
        }
    }
    
    searchOptions.FieldFilters.Add(new FieldFilter
    {
        FieldName = "containerid",
        FieldValue = $"({string.Join(" OR ", groupList.ToArray())})"
    });
    
    var results = Apis<ISearchResults>.List(searchOptions);
    
    ...