【问题标题】:Group by my json object and get the count of each group按我的 json 对象分组并获取每个组的计数
【发布时间】:2017-07-24 06:01:30
【问题描述】:

我正在使用 2 个 rest api 服务。第一个将从名为“主要类别”的列表中获取项目,如下所示:-

/test/_api/web/lists/getbytitle('MainCategory')/items?$select=Title

它将返回以下json:-

{
    "d": {
        "results": [
            {                    
                "FileSystemObjectType": 0,
                "Id": 15,
                "ID": 15,
                "ContentTypeId": "0x010006DDBDD3BDC9914B92E911733F2A56E1",
                "Title": "A",
                "Modified": "2017-03-01T12:08:35Z",
                "Created": "2017-03-01T12:08:35Z",
                "AuthorId": 1,
                "EditorId": 1,
                "OData__UIVersionString": "1.0",
                "Attachments": false,
                "GUID": "c93d9db6-efd8-4b49-9024-f8cc30c0a48e"
            },
            {
                 "FileSystemObjectType": 0,
                "Id": 16,
                "ID": 16,
                "ContentTypeId": "0x010006DDBDD3BDC9914B92E911733F2A56E1",
                "Title": "B",
                "Modified": "2017-03-01T12:10:27Z",
                "Created": "2017-03-01T12:10:27Z",
                "AuthorId": 1,
                "EditorId": 1,
                "OData__UIVersionString": "1.0",
                "Attachments": false,
                "GUID": "a023853c-e967-4db8-8414-a7c390dcc09a"
            },

我还有另一个名为 Pages 的列表,其中每个页面都链接到一个主要类别项目。

/test/_api/web/lists/getbytitle('pages')/items??$select=Title,MainCategory&$filter=MainCategory eq

这里是返回的json:-

{
    "d": {
        "results": [
            {    
                "Title": "Home",
                "MainCategory": "A"
            },
            {    
                "Title": "ewrwe",
                "MainCategory": "A"
            },
            {    
                "Title": "tgtg",
                "MainCategory": "A"
            },
            {    
                "Title": "dsdfsfdfsdfsdfsdfsdsdfsd",
                "MainCategory": "A"
            },
            {    
                "Title": "jk",
                "MainCategory": "A"
            }
        ]
    }
}

现在我想显示一个表格,显示每个类别下的页数。所以我实现了以下,它执行以下操作:-

  1. 获取所有主要类别。
  2. 为每个主要类别再次调用页面列表以获取相关页面并计算结果。

这是我的脚本:-

<script>
$(document).ready(function() {
  function getCurrentMainCategoryID() {    
    var results = "";
    var html = "";
    html = "<table style='margin-left:20%;width:50%;boarder:3px solid'><th style='text-align:left'>Main Category</th><th></th><th style='text-align:left'>Pages</th>";
    var url = "/test/_api/web/lists/getbytitle('MainCategory')/items?$select=Title";

    $.ajax({
      url: url,
      method: "GET",
      async: false,
      headers: {
        "Accept": "application/json; odata=verbose"
      },
      success: function(data) {
        if (data.d.results.length > 0) {    
          results = data.d.results;
          for (var j2 = 0; j2 < results.length; j2++) {    
            var currentMainCatTitle = results[j2].Title;

            $.ajax({
              url: "/test/_api/web/lists/getbytitle('pages')/items??$select=Title,MainCategory&$filter=MainCategory eq " + "'" + currentMainCatTitle + "'",
              method: "GET",
              async: false,
              headers: {
                "Accept": "application/json; odata=verbose"
              },
              success: function(data) {
                if (data.d.results.length > 0) {
                  html = html + "<tr><td>" + "</td>" + "<td>  </td><td>" + data.d.results.length + "</td></tr>";
                }
              },
              error: function(data) {
              }
            });
          }    
        }    
      },
      error: function(data) {
      }
    });
    $("#inserthere").after(html + "</table>");

    return results;
  }

  getCurrentMainCategoryID();
});
</script>

现在我的脚本将显示正确的结果。但我面临一个性能问题,因为我正在为每个主要类别发起单独的调用。 所以我不确定我是否可以修改我的脚本来执行以下操作:-

  1. 获取所有主要类别(我目前正在这样做)。
  2. 一次获取所有页面。而不是单独获取每个主要类别的页面..
  3. 在脚本中根据页面的主要类别对页面进行分组。并将结果存储在临时变量中
  4. 遍历主要类别项目,并为每个主要类别项目从第 3 步中的 temp 变量中获取其计数...

请问有人可以就此提出建议吗?如何根据主要类别对我的 json 进行分组?

【问题讨论】:

  • 您获得了多少个类别?是不是结果太多?也许你可以为你的桌子使用分页
  • @Gonzalo.- 这不是关于我有多少类别,而是关于为每个类别进行单独的 api 调用......这效率不高......所以我想得到所有页面使用单个 api 调用,并在 javascript 本身上进行过滤
  • @johnG 检查我的答案。我希望它会按照您的期望工作。
  • 如果您拥有该 API,请考虑实施 GraphQL。做你要求的事情会变得愚蠢。
  • 如果您使用基于 SQL 的数据存储,最好的办法是在一个查询中获取所有数据(使用 JOIN)。如果您使用像 sequelize 这样的库,它会为您完成所有繁重的工作。然后,您可以创建视图和索引以在 db 级别优化此查询。

标签: javascript jquery json rest


【解决方案1】:

如果您想进行最少数量的 ajax 调用,您只需要进行两次,正如您所说的(尽管如果您真的非常想要,您可以只使用一次)。关键是嵌套它们:所以第一个成功触发第二个,然后第二个成功响应显示结果。

我会做如下的事情。在这里,我只是显示主要类别的 GUID,以及匹配页面的计数,如果我理解正确,这基本上就是您所追求的。

var mainCategorySimulatedResponse = {
  "d": {
    "results": [{
      "FileSystemObjectType": 0,
      "Id": 15,
      "ID": 15,
      "ContentTypeId": "0x010006DDBDD3BDC9914B92E911733F2A56E1",
      "Title": "A",
      "Modified": "2017-03-01T12:08:35Z",
      "Created": "2017-03-01T12:08:35Z",
      "AuthorId": 1,
      "EditorId": 1,
      "OData__UIVersionString": "1.0",
      "Attachments": false,
      "GUID": "c93d9db6-efd8-4b49-9024-f8cc30c0a48e"
    }, {
      "FileSystemObjectType": 0,
      "Id": 16,
      "ID": 16,
      "ContentTypeId": "0x010006DDBDD3BDC9914B92E911733F2A56E1",
      "Title": "B",
      "Modified": "2017-03-01T12:10:27Z",
      "Created": "2017-03-01T12:10:27Z",
      "AuthorId": 1,
      "EditorId": 1,
      "OData__UIVersionString": "1.0",
      "Attachments": false,
      "GUID": "a023853c-e967-4db8-8414-a7c390dcc09a"
    }]
  }
}

var pagesSimulatedResponse = {
  "d": {
    "results": [{
      "Title": "Home",
      "MainCategory": "A"
    }, {
      "Title": "ewrwe",
      "MainCategory": "A"
    }, {
      "Title": "tgtg",
      "MainCategory": "A"
    }, {
      "Title": "dsdfsfdfsdfsdfsdfsdsdfsd",
      "MainCategory": "A"
    }, {
      "Title": "jk",
      "MainCategory": "A"
    }, {
      "Title": "Cliff Curtis",
      "MainCategory": "B"
    }, {
      "Title": "Martin Henderson",
      "MainCategory": "B"
    }]
  }
}


$(document).ready(function() {

  function showMainCategoryData() {

    var mainCategories, pages;

    /*
    // Make nested ajax calls here, one for Main Categories, the other for Pages.
    $.ajax({
      url: url,
      ...
      success: function(data) {

        if (data.d.results.length > 0) {
          // store Main Categories data
          mainCategories = data.d.results;

          // call nested `Pages` ajax (only runs with Main Categories successful response)
          $.ajax({
            url: url,
            ...
            success: function(data) {
              if (data.d.results.length > 0) {
                // store Pages data
                pages = data.d.results;

                // display results
                displayResults();

              } else {
                console.log('Pages returned no data');
              }
            },
            error: function(data) {}
          });
        } else {
          console.log('MainCategories returned no data');
        }
      },
      error: function(data) {}
    }); 
    */

    function displayResults() {
      var results = "";
      var html = "<table class='mainCatTable'><th class='mainCatHdr'>Main Category</th><th class='mainCatHdr'>Pages</th>";

      //loop over Main Categories
      for (var catIdx = 0; catIdx < mainCategories.length; catIdx++) {

        var pageCount = 0;

        for (var pageIdx in pages) {
          if (pages[pageIdx].MainCategory == mainCategories[catIdx].Title)
            pageCount++;
        }

        html += "<tr><td class='padRight'>" + mainCategories[catIdx].GUID + "</td>" + "<td>" + pageCount + "</td></tr>";
      }

      $("#inserthere").append(html + "</table>");
    }

    /*************** emulation code only ***************/
    // emulate above ajax calls    
    function ajaxCatSuccess(data) {
      if (data.d.results.length > 0) {
        // store Main Categories data
        mainCategories = data.d.results;

        // emulate call to nested `Pages` ajax
        ajaxPageSuccess(pagesSimulatedResponse);

      } else {
        console.log('MainCategories returned no data');
      }
    }

    function ajaxPageSuccess(data) {
      if (data.d.results.length > 0) {
        // store Pages data
        pages = data.d.results;

        // display results
        displayResults();

      } else {
        console.log('Pages returned no data');
      }
    }

    // trigger first simulated ajax call

    ajaxCatSuccess(mainCategorySimulatedResponse)
    /************ end of emulate code ***************/

  }

  showMainCategoryData();

});
.mainCatTable {
  margin-left: 10%;
  width: 80%;
  border: 3px solid
}

.mainCatHdr {
  text-align: left
}

.padRight {
  padding-right: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="inserthere"></div>

【讨论】:

  • 请注意,您可以使用.append() 在目标内部插入html,而不是使用.after(),后者将其放置在目标元素之后
  • 如果我稍微改进一下,我会将数据作为参数传递给displayResults 函数:displayResults(mainCategories, pages)。这样数据流就更明确了。
  • @K Scandrett 工作得很好,现在性能提升了很多.. 谢谢
【解决方案2】:

也许清理您的代码会有所帮助?我的想法是将您需要进行的所有调用放入一个数组中,然后异步映射 api 调用,然后您将更快地取回所有页面。您需要使getPages 的映射并行发生。

<script>
$(document).ready(function() {

  function getCurrentMainCategoryID() {

    var results = "";
    var html = "<table style='margin-left:20%;width:50%;boarder:3px solid'><th style='text-align:left'>Main Category</th><th></th><th style='text-align:left'>Pages</th>";
    var url = "/test/_api/web/lists/getbytitle('MainCategory')/items?$select=Title";

    $.ajax({
      url: url,
      method: "GET",
      async: false,
      headers: {
        "Accept": "application/json; odata=verbose"
      },
      success: function(data) {

        var getTitle = result => result.Title;
        var results = data.d.results;
        var titles = results.map(getTitle);

        // not sure if it will be done in parallel
        // look for a library async.js vs parallel.js ???
        titles.map(title => getPages(title)) 

      }
    });

    $("#inserthere").after(html + "</table>");

    return results;
  });

  function getPages(title) {
    $.ajax({
      url: "/test/_api/web/lists/getbytitle('pages')/items??$select=Title,MainCategory&$filter=MainCategory eq " + "'" + title + "'",
      method: "GET",
      async: false,
      headers: {
        "Accept": "application/json; odata=verbose"
      },
      success: function(data) {
        if (data.d.results.length > 0) {
          html = html + "<tr><td>" + "</td>" + "<td>  </td><td>" + data.d.results.length + "</td></tr>";
        }
      }
    });
  }

  getCurrentMainCategoryID();
});
</script>

如果您想将元素分组到对象数组中,只需更新您的第二个 ajax 调用以创建数据对象,并在第一个映射中覆盖 mainCat 以创建所需分组的数组:

$(document).ready(function() {

  function getCurrentMainCategoryID() {

    var grouped;
    var html = "<table style='margin-left:20%;width:50%;boarder:3px solid'><th style='text-align:left'>Main Category</th><th></th><th style='text-align:left'>Pages</th>";
    var url = "/test/_api/web/lists/getbytitle('MainCategory')/items?$select=Title";

    $.ajax({
      url: url,
      method: "GET",
      async: false,
      headers: {
        "Accept": "application/json; odata=verbose"
      },
      success: function(data) {
        var getTitle = result => result.Title;
        var results = data.d.results;
        var titles = results.map(getTitle);

        grouped = titles.map(title => {
          return {title: title, results: getPages(title)}
        });

        console.log(grouped);
      }
    });

    $("#inserthere").after(html + "</table>");

    return grouped;
  });

  function getPages(title) {

    var resultsObject;

    $.ajax({
      url: "/test/_api/web/lists/getbytitle('pages')/items??$select=Title,MainCategory&$filter=MainCategory eq " + "'" + title + "'",
      method: "GET",
      async: false,
      headers: {
        "Accept": "application/json; odata=verbose"
      },
      success: function(data) {
        resultsObject = {
          pages: data.d.results,
          length: data.d.results.length
        }
      }
    });

    return resultsObject;
  }

  getCurrentMainCategoryID();
});

样本分组

[
  {
    title: _,
    results: {
      pages: [...],
      length: n
    }
  }, {
    title: _,
    results: {
      pages: [...],
      length: n
    }
  },
]

如果您在一次调用中取回所有数据,则可以查询mainCategories 和组。

分组示例代码

function getMainCat(data, cat) {
  let grouped = data.reduce((acc, item) => {
    let selection = Object.keys(item).reduce((acc, key) => {

      let results = item[key].results;
      let pages = results.filter(result => result["MainCategory"] == cat);

      let select = {
        title: key,
        results: {
          pages: pages,
          length: pages.length
        }
      }

      return acc.concat(select);
    }, []);

    return acc.concat(selection);
  }, []);

  return grouped;
}

let data = [
  {
    "d": {
      "results": [
        {
          "Title": "Home",
          "MainCategory": "A"
        }, {
          "Title": "ewrwe",
          "MainCategory": "A"
        }, {
          "Title": "tgtg",
          "MainCategory": "A"
        }, {
          "Title": "dsdfsfdfsdfsdfsdfsdsdfsd",
          "MainCategory": "A"
        }, {
          "Title": "jk",
          "MainCategory": "B"
        }
      ]
    }
  }
]

console.log("searching A: ");
console.log(getMainCat(data, 'A'));
console.log("searching B: ");
console.log(getMainCat(data, 'B'));
console.log("searching C: ");
console.log(getMainCat(data, 'C'));

这是一个总体建议,我喜欢这段代码的清理方式!

【讨论】:

  • 但我认为仍然在您的代码中,将为每个主类别启动单独的 api 调用,这是正确的吗?所以仍然会为每个主类别调用 getPages() 函数。所以这不会解决我面临的性能问题
  • @johnG 是的,我相信你是对的,我不完全确定该怎么做,但有一种方法可以让 map 并行发生,你应该研究一下
  • 所以你的意思是你的代码中的titles.forEach(title => getPages(title));不会导致调用并行发生??
  • 但我的问题不是关于执行并行请求(这也可能有性能缺陷)..但我问我是否可以获得所有页面的标题和主类别..然后在javascript .. 所以在这种情况下,我只会做 2 个 api 调用;一个获取所有主要类别,另一个调用获取所有页面..然后在脚本本身内部,我可以根据主类别对页面进行分组,并计算每个主类别的结果,而无需进行额外的 api 调用,这是可能吗?
  • @johnG 我更新了代码,这应该为您提供这些分组对象的数组
【解决方案3】:

一些建议:

  • 不是每次都根据mainCategory API 调用响应调用Pages API 调用。您只能调用这两个 API(mainCategory 和 pages)一次以提高应用程序的性能。
  • 您可以异步调用这两个 API 来获取页面加载数据。

    $(document).ready(function() {
      function getCurrentMainCategoryID() {
    var url = "/test/_api/web/lists/getbytitle('MainCategory')/items?$select=Title";
    $.ajax({
      url: url,
      method: "GET",
      headers: {
        "Accept": "application/json; odata=verbose"
      },
      success: function(data) {
        if (data.d.results.length > 0) {
          var mainCategoriesData = data.d.results;
          getPagesData();
        } else {
          console.log('MainCategories returned no data');
        }
    
        function getPagesData() {
          var url = "/test/_api/web/lists/getbytitle('pages')/items";
          $.ajax({
            url: url,
            method: "GET",
            headers: {
              "Accept": "application/json; odata=verbose"
            },
            success: function(data) {
              if (data.d.results.length > 0) {
                var pagesData = data.d.results;
              } else {
              console.log('Pages returned no data');
              }
            }
        });
        }
      }
    });
    

现在,您拥有pages 数据和main category 数据。

var mainCategoriesData = [
            {                    
                "FileSystemObjectType": 0,
                "Id": 15,
                "ID": 15,
                "ContentTypeId": "0x010006DDBDD3BDC9914B92E911733F2A56E1",
                "Title": "A",
                "Modified": "2017-03-01T12:08:35Z",
                "Created": "2017-03-01T12:08:35Z",
                "AuthorId": 1,
                "EditorId": 1,
                "OData__UIVersionString": "1.0",
                "Attachments": false,
                "GUID": "c93d9db6-efd8-4b49-9024-f8cc30c0a48e"
            },
            {
                 "FileSystemObjectType": 0,
                "Id": 16,
                "ID": 16,
                "ContentTypeId": "0x010006DDBDD3BDC9914B92E911733F2A56E1",
                "Title": "B",
                "Modified": "2017-03-01T12:10:27Z",
                "Created": "2017-03-01T12:10:27Z",
                "AuthorId": 1,
                "EditorId": 1,
                "OData__UIVersionString": "1.0",
                "Attachments": false,
                "GUID": "a023853c-e967-4db8-8414-a7c390dcc09a"
            }];

var pagesData = [
            {    
                "Title": "Home",
                "MainCategory": "A"
            },
            {    
                "Title": "ewrwe",
                "MainCategory": "A"
            },
            {    
                "Title": "tgtg",
                "MainCategory": "A"
            },
            {    
                "Title": "dsdfsfdfsdfsdfsdfsdsdfsd",
                "MainCategory": "A"
            },
            {    
                "Title": "jk",
                "MainCategory": "A"
            }
        ];

使用for ... in 循环,您可以迭代响应并根据main category 获取page counts。

演示

var mainCategoriesData = [
            {                    
                "FileSystemObjectType": 0,
                "Id": 15,
                "ID": 15,
                "ContentTypeId": "0x010006DDBDD3BDC9914B92E911733F2A56E1",
                "Title": "A",
                "Modified": "2017-03-01T12:08:35Z",
                "Created": "2017-03-01T12:08:35Z",
                "AuthorId": 1,
                "EditorId": 1,
                "OData__UIVersionString": "1.0",
                "Attachments": false,
                "GUID": "c93d9db6-efd8-4b49-9024-f8cc30c0a48e"
            },
            {
                 "FileSystemObjectType": 0,
                "Id": 16,
                "ID": 16,
                "ContentTypeId": "0x010006DDBDD3BDC9914B92E911733F2A56E1",
                "Title": "B",
                "Modified": "2017-03-01T12:10:27Z",
                "Created": "2017-03-01T12:10:27Z",
                "AuthorId": 1,
                "EditorId": 1,
                "OData__UIVersionString": "1.0",
                "Attachments": false,
                "GUID": "a023853c-e967-4db8-8414-a7c390dcc09a"
            }];

var pagesData = [
            {    
                "Title": "Home",
                "MainCategory": "A"
            },
            {    
                "Title": "ewrwe",
                "MainCategory": "A"
            },
            {    
                "Title": "dkjfkdf",
                "MainCategory": "B"
            },            
            {    
                "Title": "tgtg",
                "MainCategory": "A"
            },
            {    
                "Title": "dsdfsfdfsdfsdfsdfsdsdfsd",
                "MainCategory": "A"
            },
            {    
                "Title": "slkfjrel",
                "MainCategory": "B"
            },            
            {    
                "Title": "jk",
                "MainCategory": "A"
            }
        ];			
        
var resArr = [];  
var count = 1;
for (var i in mainCategoriesData) {
  for (var j in pagesData) {
    if(pagesData[j].MainCategory == mainCategoriesData[i].Title) {
      mainCategoriesData[i].pagesCount = count++;
    }
  }
  count = 1;
  resArr.push({
    "Main Category": mainCategoriesData[i].Title,
    "PagesCount": mainCategoriesData[i].pagesCount
  })
}        

console.log(resArr);

【讨论】:

    【解决方案4】:

    使用jQuery.getJSON() 它将返回已解析的对象。您只需要两个 ajax 调用。修改 url 并删除您想要一次获取所有页面的类别的过滤器。

    var results = [];
    var html = "<table style='margin-left:20%;width:50%;boarder:3px solid'><th style='text-align:left'>Main Category</th><th></th><th style='text-align:left'>Pages</th>";
    
    $.getJSON( "/test/_api/web/lists/getbytitle('MainCategory')/items?$select=Title")
      .done(function( categories ) {
        var mainCategoryResults = categories.d.results;
        $.getJSON( "/test/_api/web/lists/getbytitle('pages')/items?$select=Title,MainCategory")
          .done(function( pages ) {
            var pageResults = pages.d.results;      
            $(mainCategoryResults).each(function(k,v){
                var i=0;
                $(pageResults).each(function(key,val){
                    if(v['Title'] === val['MainCategory']){
                        i++;
                    }
                });
            results.push([v.Title,i]);
            });       
          })
          .fail(function( jqxhr, textStatus, error ) {
            var err = textStatus + ", " + error;
            console.log( "Pages Request Failed: " + err );
        });     
      })
      .fail(function( jqxhr, textStatus, error ) {
        var err = textStatus + ", " + error;
        console.log( "Categories Request Failed: " + err );
    });
    

    您可以在下面的 sn-p 中测试创建结果的双 each() 循环。

    var a = {
      "d": {
        "results": [{
            "FileSystemObjectType": 0,
            "Id": 15,
            "ID": 15,
            "ContentTypeId": "0x010006DDBDD3BDC9914B92E911733F2A56E1",
            "Title": "A",
            "Modified": "2017-03-01T12:08:35Z",
            "Created": "2017-03-01T12:08:35Z",
            "AuthorId": 1,
            "EditorId": 1,
            "OData__UIVersionString": "1.0",
            "Attachments": false,
            "GUID": "c93d9db6-efd8-4b49-9024-f8cc30c0a48e"
          },
          {
            "FileSystemObjectType": 0,
            "Id": 16,
            "ID": 16,
            "ContentTypeId": "0x010006DDBDD3BDC9914B92E911733F2A56E1",
            "Title": "B",
            "Modified": "2017-03-01T12:10:27Z",
            "Created": "2017-03-01T12:10:27Z",
            "AuthorId": 1,
            "EditorId": 1,
            "OData__UIVersionString": "1.0",
            "Attachments": false,
            "GUID": "a023853c-e967-4db8-8414-a7c390dcc09a"
          }
        ]
      }
    };
    var b = {
      "d": {
        "results": [{
            "Title": "Home",
            "MainCategory": "A"
          },
          {
            "Title": "ewrwe",
            "MainCategory": "A"
          },
          {
            "Title": "tgtg",
            "MainCategory": "A"
          },
          {
            "Title": "dsdfsfdfsdfsdfsdfsdsdfsd",
            "MainCategory": "A"
          },
          {
            "Title": "jk",
            "MainCategory": "A"
          }
        ]
      }
    };
    var c = [];
    $(a.d.results).each(function(k, v) {
      var i = 0;
      $(b.d.results).each(function(key, val) {
        if (v['Title'] === val['MainCategory']) {
          i++;
        }
      });
      c.push([v.Title, i]);
    });
    console.log(c);
    &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

    【讨论】:

      猜你喜欢
      • 2017-09-29
      • 1970-01-01
      • 2021-10-04
      • 1970-01-01
      • 1970-01-01
      • 2021-03-13
      • 2020-09-22
      • 1970-01-01
      • 2021-08-07
      相关资源
      最近更新 更多