sortingsharepointpaginationcsomcaml

Folders first in paged results using CamlQuery and ListItemCollectionPosition


I'm implementing paging using CamlQuery and ListItemCollection, sorting results by the name field. I would like folders to come first, as they do in UI, e.g. "folder A2, folder B2, file A1, file B1", but instead I get "file A1, folder A2, file B1, folder B2".

What is the best way to accomplish such sorting and paging? Note that for paging I have to specify the value of the sorting field which will be the first record of the page – I've considered adding two sorting fields into CAML, but I'm not sure whether I can use two fields in ListItemCollectionPosition.PagingInfo.

The code I'm currently using is like this:

var queryText = @"
   <View> 
       <Query> 
           <OrderBy Override='TRUE'> 
               <FieldRef Name='FileLeafRef' Ascending='True' />
           </OrderBy> 
       </Query> 
           ...
       <RowLimit> 
           10
       </RowLimit> 
   </View>";
var camlQuery = new CamlQuery();
camlQuery.ViewXml = queryText;
camlQuery.ListItemCollectionPosition = new ListItemCollectionPosition
    {
        PagingInfo = "Paged=TRUE&p_ID=1002&p_FileLeafRef=A1"
    };
var items = list.GetItems(camlQuery);

Solution

  • For getting results sorted by object type you could utilize FSObjType property, for example the following CAML expressions tells server to return folder items first and then file items:

    <OrderBy Override='TRUE'> 
         <FieldRef Name='FSObjType' Ascending='False' />
    </OrderBy>
    

    Regarding ListItemCollectionPosition.PagingInfo property, the following expression tells to return items that come after the item with ID specified via p_ID parameter and sorted by object type:

    var camlQuery = new CamlQuery();
    camlQuery.ListItemCollectionPosition = new ListItemCollectionPosition
    {
       PagingInfo = "Paged=TRUE&p_FSObjType=1&p_ID=200"
    }; 
    

    Example

    The following example returns 200 items:

    Code:

    var itemsCount = 200;
    var startItemId = 100;
    
    var queryText = @"
    <View> 
       <Query> 
           <OrderBy Override='TRUE'> 
               <FieldRef Name='FSObjType' Ascending='False' />
           </OrderBy> 
       </Query> 
       <RowLimit> 
           {0}
       </RowLimit> 
    </View>";
    
     var camlQuery = new CamlQuery
     {
           ViewXml = string.Format(queryText, itemsCount),
           ListItemCollectionPosition = new ListItemCollectionPosition
           {
               PagingInfo = $"Paged=TRUE&p_FSObjType=1&p_ID={startItemId - 1}"
           }
     };
     var items = list.GetItems(camlQuery);
     ctx.Load(items);
     ctx.ExecuteQuery();    
    

    Update

    The example of PagingInfo expression for items to be sorted by type first and then by name:

    Paged=TRUE&p_FSObjType=1&p_FileLeafRef=B2&p_ID=100