Can't retrieve all Items from all lists that reside on a single subsite
-
30-01-2021 - |
Question
SP Community, I am absolutely stumped and desperate for help. I have been up and down StackExchange trying to get 3 separate attempts to - 1. query all of the lists within a subsite and to then - 2. filter the query based on criteria in the title.
I need to retrieve all items within each list in a subsite. Once I do that, I need to filter by list title so that only information from lists containing "RDTEN" or "procurement" in their title get parsed. With the end result, I need to build a graph for the aggregated information.
Please see attempts below, these are my starting points, none of which are currently working:
AJAX Test with Multiple Lists - Ajax
<script type="text/javascript">
var siteUrl = 'https://site/subsite';
// Load the required SharePoint libraries.
$(document).ready(function () {
// The js files are in a URL in the form:
// web_url/_layouts/15/resource_file
var scriptbase = siteUrl + "/_layouts/15/";
// Load the js files and continue to
// the execOperation function.
$.getScript(scriptbase + "SP.Runtime.js",
function () {
$.getScript(scriptbase + "SP.js", execOperation);
}
);
});
// Function to execute basic operations.
function execOperation() {
// Continue your program flow here.
retrieveWebSiteProperties(siteUrl);
}
function retrieveWebSiteProperties(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
this.oWebsite = clientContext.get_web();
this.collList = oWebsite.get_lists();
this.listInfoCollection = clientContext.load(collList);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onQuerySucceeded(sender, args) {
var listInfo = '';
var listEnumerator = this.collList.getEnumerator();
while (listEnumerator.moveNext()) {
var oList = listEnumerator.get_current();
listInfo += 'Title: ' + oList.get_title() + ' Created: ' +
oList.get_created().toString() + '\n';
}
$("#chartArea").html(listInfo);
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
</script>
<body>
<div id="chartArea"></div>
</body>
CSOM
<script type="text/javascript">
var context;
var web;
var collList;
$(document).ready(function () {
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', getLists);
});
function getLists() {
context = new SP.ClientContext.get_current();
web = context.get_web();
collList = web.get_lists();
context.load(collList);
context.executeQueryAsync(onRequestSuccess, onRequestFailure);
}
function onRequestSuccess() {
var listInfo = '';
var listEnumerator = collList.getEnumerator();
while (listEnumerator.moveNext()) {
var oList = listEnumerator.get_current();
if(oList.get_title().indexOf("pro") !== -1){ //if title contains "pro"
listInfo += '<div>Title: ' + oList.get_title() + ' Created: ' +
oList.get_created().toString() + '</div>';
}
}
$("#chartArea").html(listInfo);
}
function onRequestFailure(sender, args) {
$("#chartArea").html('Request failed. ' + args.get_message() + '\n' +
args.get_stackTrace());
}
</script>
<body>
<div id="chartArea"></div>
</body>
REST
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test with Multiple Lists - Rest</title>
</head>
<script type="text/javascript">
// Set the REST endpoint to use.
// This one includes a filter to only return lists whose title includes "Site"
var url = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists?
$filter=substringof('Site',
Title)";
// Create the AJAX request using jQuery.
var request = jQuery.ajax({ url: url, headers: { "Accept":
"Application/json;odata=nometadata" } });
// Use a .then() callback to do something with data after its returned by the server
request.then(
function (d) {
// For each result in the set of returned data
d.value.forEach(
function (i) {
// Print the Title of the list to the console
console.log(i.Title);
});
});
</script>
<body>
<div id="chartArea"></div>
</body>
Note: My original question was put on hold for being unclear, I wrote a new question in hopes to provide additional clarity.
Solution
I've got a script here that'll do most of what you're looking for. Currently it doesn't create a graph or any fancy stuff but it does collect the info you're looking for. Be careful that your internal column name actually is Title
or you'll have to change it in the for loops in getSPListData_SecondQuery_Success
.
The only things you'll really need to change is the variables siteUrl
, and potentially expr
. The data from each list is sent to the manageData
function under allData
whereas the items that meet your criteria will be sent to oListData
.
siteUrl
must be the absolute url of the site, without including the page. For example: http://mySites/sample/infrastructure rather than http://mySites/sample/infrastructure/home.aspx.
expr
is a regex expression. In this case it's saying find any instance of "RDTEN" or "procurement", case insensitive. If you need help with regex expressions, there's lots of guides you can find with a quick google search. In JS they are notated by /<pattern>/<flags>
.
In manageData
you can use console.log(allData)
or console.log(oListData)
to see what's in the respective items.
The general flow has been split into functions as I find it easier to read that way... Here's an outline:
Load JavaScript libraries with an anonymous function.
Wait for
SP.js
to load forSP.ClientContext
to be loaded, then callgetSPListData
getSPListData :: Prepare and execute the first query to gather all the lists.
If successful, send current context to
getSPListData_SecondQuery
and prepare second queryIf failed, log the issue through
getSPListData_LogError
.getSPListData_SecondQuery :: Prepare and execute second query to gather all items in lists.
If successful, send current context to
getSPListData_SecondQuery_Success
to process the list items.If failed, log the issue through
getSPListData_LogError
.getSPListData_SecondQuery_Success :: Process items by looking at the title of every list item. If matches, push into a list.... Once complete, push the valid list data (
oListData
) and all item (result
, orallData
in the next function) tomanageData
.manageData :: Used to manipulate the list items in the array. Can use
console.log(oListItems)
orconsole.log(allData)
to view whats in the respective arrays in the console. Currently puts the first 5 into a list wherever your Code Editor is on the page.
This isn't the most efficient evaluation as it does the two queries which can take time, and then at the end it has a rather large run-time complexity from the nested for loops. If you've got a lot of lists or items, you may need to optimize some of it.
Just paste and edit this into a Script Editor on whatever page you want. Right now it creates a div to send the data to in the form of...
Title = itemTitle
Library = relativeUrl
Blank Line
Heres the script:
Files: <br/><div id="listItemData"></div><br/>
<script type="text/javascript">
// Loads libraries from CDNs...
javascript: ( function() {
function l( u, i ) {
var d = document;
if ( !d.getElementById( i ) ) {
var s = d.createElement( 'script' );
s.src = u;
s.id = i;
s.async = true;
d.body.appendChild( s );
}
}
// l( url, idForElem )
l( '//ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js', 'msAjax' )
l( '//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js', 'jQuery' )
} )();
// Wait for SP.js to finish loading before we run the queries.
SP.SOD.executeOrDelayUntilScriptLoaded( getSPListData, 'SP.js' );
function getSPListData() {
// Set up the first query
this.result = [];
this.siteUrl = 'http(s)://mySite/sample/subSite'; // Change this to your subsite in question.
this.ctx = new SP.ClientContext( siteUrl )
this.lists = ctx.get_web().get_lists();
this.expr = /(RDTEN)|(procurement)/i // This is what you're searching for in the Title field, "i" for case insensitive search.
this.ctx.load( this.lists, "Include(Id,Title)" );
ctx.executeQueryAsync(
this.getSPListData_SecondQuery.bind(this),
this.getSPListData_LogError.bind(this)
);
}
function getSPListData_SecondQuery(sender, args){
lists.get_data().forEach( function( list ) {
// Set up the second query and push its results into the "Result" array
var items = list.getItems( SP.CamlQuery.createAllItemsQuery() );
ctx.load( items );
// This entry is the list's base data
var listEntry = {
id: list.get_id().toString(),
title: list.get_title()
}
// Push the data into result, items will have all items in each list.
result.push( {
list: listEntry,
items: items
} );
} );
ctx.executeQueryAsync(
this.getSPListData_SecondQuery_Success.bind(this),
this.getSPListData_LogError.bind(this)
);
}
function getSPListData_SecondQuery_Success(sender, args){
//transform listitem properties. This is where the "items" section of "Result" is filled out.
result.forEach( function( item ) {
item.items = item.items.get_data().map( function( listItem ) {
return listItem.get_fieldValues();
} );
} );
// Filter each by the ReGex expression earlier on the Title field.
var oListData = [];
var itemTitle;
for ( listNum = 0, listTot = result.length; listNum < listTot; listNum++ ) {
for ( itemNum = 0, itemTot = result[ listNum ].items.length; itemNum < itemTot; itemNum++ ) {
itemTitle = result[ listNum ].items[ itemNum ].Title
if ( itemTitle && itemTitle.match( expr ) ) {
// put data into a list
oListData.push( result[ listNum ].items[ itemNum ] )
}
}
}
// Here's where you can make the data visible. in the manageData function.
manageData( oListData, result );
}
// incase an error comes up in the execution of the queries
function getSPListData_LogError( sender, args ) {
console.log( args.get_message() );
}
function manageData( oListData, allData ) {
// Do stuff with list items here...
var oListDataField = document.getElementById( "listItemData" );
var stringBuilding = '';
for(i=0, itemMax = Math.min(5, oListData.length); i < itemMax; i++){
stringBuilding += " Title = " + oListData[i].Title + "<br/>"
stringBuilding += " Library = " + oListData[i].FileDirRef + "<br/><br/>"
}
oListDataField.innerHTML = stringBuilding
// For seeing the relative data:
console.log(allData)
console.log(oListData)
}
</script>