web-dev-qa-db-ja.com

JSONデータのJavaScript SUMおよびGROUP BY

これは、いくつかのJSONデータオブジェクトを使用してJavaScriptを実行する最初の試みであり、私の目標を達成するための適切な方法についていくつかのアドバイスが必要です。

一部のサーバー側コードは、実際に操作して文字列に割り当てる必要があるJSON形式の文字列を生成します。

var dataString='$DATASTRING$';

しかし、サーバーがそのデータを置き換えた後に処理しなければならない最終結果(もちろん\ r\nなし):

var dataString='[ 
 { "category" : "Search Engines", "hits" : 5, "bytes" : 50189 },
 { "category" : "Content Server", "hits" : 1, "bytes" : 17308 },
 { "category" : "Content Server", "hits" : 1, "bytes" : 47412 },
 { "category" : "Search Engines", "hits" : 1, "bytes" : 7601 },
 { "category" : "Business", "hits" : 1, "bytes" : 2847 },
 { "category" : "Content Server", "hits" : 1, "bytes" : 24210 },
 { "category" : "Internet Services", "hits" : 1, "bytes" : 3690 },
 { "category" : "Search Engines", "hits" : 6, "bytes" : 613036 },
 { "category" : "Search Engines", "hits" : 1, "bytes" : 2858 } 
]';

そして、それを操作するオブジェクトに変更できます。

var dataObject=eval("("+dataString+")");

これにより、データの個々の行のデータにアクセスできますが、値を合計、グループ化、順序付けする必要があります。

次のようなSQLステートメントに相当するものが必要です。

SELECT category, sum(hits), sum(bytes) 
FROM dataObject
GROUP BY category
ORDER BY sum(bytes) DESC

私の望ましい出力は、さらに処理できる次のようなオブジェクトです。

var aggregatedObject='[ 
 { "category" : "Search Engines", "hits" : 13, "bytes" : 673684 },
 { "category" : "Content Server", "hits" : 3, "bytes" : 88930 },
 { "category" : "Internet Services", "hits" : 1, "bytes" : 3690 },
 { "category" : "Business", "hits" : 1, "bytes" : 2847 } 
]';

...しかし、どこから始めればよいかわかりません。

すべてのカテゴリ値をループして最初に一意のカテゴリを見つけ、次にループしてヒット数とバイト数を合計し、次にもう一度ソートすることもできますが、もっと簡単な方法があるはずです。

prototype.js(1.7)はすでにクライアントページに含まれていますが、必要に応じてUnderscore、jQuery、またはその他の小さなライブラリを追加することもできます。

クエリを処理するためのコードの量が最も少なくて、何が最善、最も簡単、最小であるかがわかりません。

助言がありますか?

23
LordChariot

ネイティブ関数.reduce()を使用してデータを集約し、次に.sort()を使用してbytesで並べ替えることができます。

_var result = dataObject.reduce(function(res, obj) {
    if (!(obj.category in res))
        res.__array.Push(res[obj.category] = obj);
    else {
        res[obj.category].hits += obj.hits;
        res[obj.category].bytes += obj.bytes;
    }
    return res;
}, {__array:[]}).__array
                .sort(function(a,b) { return b.bytes - a.bytes; });
_

古い実装をサポートしている場合は、 shim for .reduce() を使用する必要があります。

28
user1106925

LINQ.js ルートを使用する場合は、次のように実行できます。

var aggregatedObject = Enumerable.From(dataArray)
        .GroupBy("$.category", null,
                 function (key, g) {
                     return {
                       category: key,
                       hits: g.Sum("$.hits"),
                       bytes: g.Sum("$.bytes")
                     }
        })
        .ToArray();

スタックスニペットを使用したデモ:

var dataArray = [ 
  { category: "Search Engines", hits: 5, bytes: 50189 },
  { category: "Content Server", hits: 1, bytes: 17308 },
  { category: "Content Server", hits: 1, bytes: 47412 },
  { category: "Search Engines", hits: 1, bytes: 7601  },
  { category: "Business",       hits: 1, bytes: 2847  },
  { category: "Content Server", hits: 1, bytes: 24210 },
  { category: "Internet ",      hits: 1, bytes: 3690  },
  { category: "Search Engines", hits: 6, bytes: 613036 },
  { category: "Search Engines", hits: 1, bytes: 2858  } 
];

var aggregatedObject = Enumerable.From(dataArray)
        .GroupBy("$.category", null,
                 function (key, g) {
                     return {
                       category: key,
                       hits: g.Sum("$.hits"),
                       bytes: g.Sum("$.bytes")
                     }
        })
        .ToArray();

console.log(aggregatedObject);
<script src="//cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.min.js"></script>

また、 linqjs group by by a sum に関する詳細情報を見つけることができます

8
KyleMit
var obj = [{Poz:'F1',Cap:10},{Poz:'F1',Cap:5},{Poz:'F1',Cap:5},{Poz:'F2',Cap:20},{Poz:'F1',Cap:5},{Poz:'F1',Cap:15},{Poz:'F2',Cap:5},{Poz:'F3',Cap:5},{Poz:'F4',Cap:5},{Poz:'F1',Cap:5}];
Array.prototype.sumUnic = function(name, sumName){
    var returnArr = [];
    var obj = this;
    for(var x = 0; x<obj.length; x++){
        if((function(source){
            if(returnArr.length == 0){
                return true;
            }else{
                for(var y = 0; y<returnArr.length; y++){
                    var isThere = [];
                    if(returnArr[y][name] == source[name]){
                        returnArr[y][sumName] = parseInt(returnArr[y][sumName]) + parseInt(source[sumName]);
                        return false;
                    }else{
                        isThere.Push(source);
                    }
                }
                if(isThere.length>0)returnArr.Push(source);
                return false;
            }
        })(obj[x])){
            returnArr.Push(obj[x]);
        }
    }
    return returnArr;
}
obj.sumUnic('Poz','Cap');
// return "[{"Poz":"F1","Cap":45},{"Poz":"F2","Cap":25},{"Poz":"F3","Cap":5},{"Poz":"F4","Cap":5}]"
1
AhbapAldirmaz

上記のdataStringを考えると、以下のコードは機能するようです。各オブジェクトを通過します。カテゴリがgroupedObjects配列に存在する場合、そのヒットとバイトが既存のオブジェクトに追加されます。それ以外の場合は、新しいと見なされ、groupedObjects配列に追加されます。

このソリューションは、underscore.jsとjQueryを利用します

ここにjsfiddleのデモがあります: http://jsfiddle.net/R3p4c/2/

var objects = $.parseJSON(dataString);
var categories = new Array();
var groupedObjects = new Array();
var i = 0;

_.each(objects,function(obj){
    var existingObj;
    if($.inArray(obj.category,categories) >= 0) {
        existingObj = _.find(objects,function(o){return o.category === obj.category; });
        existingObj.hits += obj.hits;
        existingObj.bytes += obj.bytes;
    } else {
        groupedObjects[i] = obj;
        categories[i] = obj.category;
        i++;
  }
});

groupedObjects = _.sortBy(groupedObjects,function(obj){ return obj.bytes; }).reverse();
1
jackwanders