So, here is my complete code. I am not a professional, so maybe the code is not beautiful and could be shorter, but it works for my application.
I hope someone can use it.
// In this case, there is one main site containing one main list and many subsites, each containing a subsite-list.
// The code below fetches the items from all the subsite-lists and copies them to the main list.
// If there are items in the main list but no corresponding item in a subsite-list, the item will be deleted.
// This syncing works in one direction. Since all the lists contain a field with an URL (called 'projectsite'),
// I decided to find a match by comparing these URLs.
ExecuteOrDelayUntilScriptLoaded(RetrieveMainListItems, "sp.js");
// ************************************************************************************
// global
var listTitleSub = "TitleOfListInSubsites";
var mainURL = 'yourURL';
var listTitleMain = 'TitleOfListInMainSite';
var allMainListTitles = new Array();
var allMainListIds = new Array();
var allMainListUrls = new Array();
var clientContext = null;
var spListobj = null;
var items;
// retrieve all elements from main list
function RetrieveMainListItems() {
var clientContext = new SP.ClientContext(mainURL);
var oList = clientContext.get_web().get_lists().getByTitle(listTitleMain);
var camlQuery = new SP.CamlQuery();
this.collListItem = oList.getItems(camlQuery);
clientContext.load(collListItem);
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceededListItems),
Function.createDelegate(this, this.onQueryFailed));
}
function onQuerySucceededListItems(sender, args) {
var listItemEnumerator = collListItem.getEnumerator();
var counter = 0;
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
// collect some date for later comparing
allMainListTitles[counter] = oListItem.get_item('Title');
allMainListUrls[counter] = oListItem.get_item('Projectsite').get_url();
allMainListIds[counter] = oListItem.get_id();
counter = counter + 1;
}
RetrieveSubsites();
}
// retrieve all the subsites
function RetrieveSubsites() {
clientContext = new SP.ClientContext.get_current();
this.site = clientContext.get_web();
this.webSubSites = site.get_webs();
clientContext.load(this.webSubSites, 'Include(Title, ServerRelativeUrl)');
clientContext.executeQueryAsync(Function.createDelegate(this, this.onLoadSubWebs), Function.createDelegate(this, this.onQueryFailed));
}
// load the list in every subsite
function onLoadSubWebs(sender, args) {
items = [];
for (var x = 0; x < this.webSubSites.get_count(); x++) {
web = this.webSubSites.itemAt(x);
var siteUrl = web.get_serverRelativeUrl();
spListobj = web.get_lists().getByTitle(listTitleSub);
var spCamlQuery = new SP.CamlQuery();
var spListobjItems = spListobj.getItems(spCamlQuery);
var itemDetails = new Object;
itemDetails.ListItems = spListobjItems;
itemDetails.WebTitle = web.get_title();
items.push(itemDetails);
clientContext.load(spListobjItems);
}
clientContext.executeQueryAsync(Function.createDelegate(this, this.onLoadTaskDetails), Function.createDelegate(this, this.onQueryFailed));
}
// refresh the main list by updating existing items, adding new ones or deleting them
function onLoadTaskDetails(sender, args) {
var clientContext = new SP.ClientContext(mainURL);
var oListPR = clientContext.get_web().get_lists().getByTitle(listTitleMain);
for (var x = 0; x < items.length; x++) {
var subProjectExistsInListFlag = false;
var itemDetails = items[x]; // get a list from the array
var listItemEnumerator = itemDetails.ListItems.getEnumerator();
while (listItemEnumerator.moveNext()) { // loop through all the list elements
var oListItem = listItemEnumerator.get_current(); // this is a list item from a subsite list
var j = 0;
// check if the subsite list items are already existing in the main list by comparing the URLs
for (j=0; j<allMainListUrls.length; j++) {
var subUrlTemp = oListItem.get_item('Projectsite').get_url();
var mainUrlTemp = allMainListUrls[j]
if (subUrlTemp == mainUrlTemp) {
subProjectExistsInListFlag = true; // match found
break;
}
else {
subProjectExistsInListFlag = false;
}
}
// if the entry existst: edit
if (subProjectExistsInListFlag) {
//alert(oListItem.get_item('Title') + ' exists.');
var oListItemPR = oListPR.getItemById(allMainListIds[j]);
// copy data
oListItemPR.set_item('Title', oListItem.get_item('Title'));
oListItemPR.set_item('Projectsite', oListItem.get_item('Projectsite'));
oListItemPR.set_item('Begin', oListItem.get_item('Begin'));
oListItemPR.set_item('End', oListItem.get_item('End'));
oListItemPR.set_item('Comment', oListItem.get_item('Comment'));
// ... an so on
oListItemPR.update();
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceededFinal), Function.createDelegate(this, this.onQueryFailed));
}
// else: create new item
else {
//alert(oListItem.get_item('Title') + ' does not exist.');
var itemCreateInfo = new SP.ListItemCreationInformation();
var oListItemPR = oListPR.addItem(itemCreateInfo);
// copy data
oListItemPR.set_item('Title', oListItem.get_item('Title'));
oListItemPR.set_item('Projectsite', oListItem.get_item('Projectsite'));
oListItemPR.set_item('Begin', oListItem.get_item('Begin'));
oListItemPR.set_item('End', oListItem.get_item('End'));
oListItemPR.set_item('Comment', oListItem.get_item('Comment'));
// ... an so on
oListItemPR.update();
clientContext.load(oListItemPR);
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceededFinalWithRefresh), Function.createDelegate(this, this.onQueryFailed));
}
}
}
// if there are items in the main list, but the items in the subsites lists do not exist anymore, delete them from the main list
for (var m=0; m<allMainListUrls.length; m++) {
var mainUrlTemp = allMainListUrls[m];
var listProjectExistsInSubFlag = false;
// loop through all the subs
for (var x = 0; x < items.length; x++) {
var itemDetails = items[x];
var listItemEnumerator = itemDetails.ListItems.getEnumerator();
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
var subUrlTemp = oListItem.get_item('Project').get_url();
if (subUrlTemp == mainUrlTemp) {
listProjectExistsInSubFlag = true;
break;
}
else {
listProjectExistsInSubFlag = false;
}
}
if (listProjectExistsInSubFlag == true) break;
}
if (listProjectExistsInSubFlag) {
//alert('List in subsites matches ' + allMainListTitles[m]);
}
else {
alert('Found no subsite matching "' + allMainListTitles[m] + '". This item will be deleted.');
var oListItemPR = oListPR.getItemById(allMainListIds[m]);
oListItemPR.deleteObject();
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceededFinalWithRefresh), Function.createDelegate(this, this.onQueryFailed));
}
}
//alert("done");
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
function onQuerySucceededFinal(sender, args) {
}
function onQuerySucceededFinalWithRefresh(sender, args) {
location.href = location.href;
}