JavaScript Map / Reduce返回按计数分组

时间:2017-03-16 05:50:49

标签: javascript json node.js mapreduce reduce

我有一个JSON集合作为数组。我想按集合中的三个字段进行分组,然后返回结果以及匹配文档的计数。下面的例子有望让它更清晰。

返回了JSON文档集合:

SELECT m.id, m.name, m.marks, s.marks, e.marks,
CASE WHEN (m.marks > 75 and s.marks > 75) OR (s.marks > 75 and e.marks > 75) OR (m.marks > 75 and e.marks > 75) THEN 'Pass'
     WHEN (m.marks > 75 and (s.marks > 60 OR e.marks > 60)) OR
          (s.marks > 75 and (m.marks > 60 OR e.marks > 60)) OR
          (e.marks > 75 and (s.marks > 60 OR m.marks > 60)) THEN 'Pass'
     WHEN (m.marks < 75 and s.marks < 75 and e.marks < 75 and (m.marks < 50 or e.marks < 50 or s.marks < 50)) THEN 'Fail'
     ELSE NULL END as Merit
FROM #maths m
inner join #science s
on m.ID = s.ID
inner join #English e
on m.ID = e.ID

应该在浏览器,ipAddress和uri上执行分组,然后返回分组结果以及下面的计数(我检查了几次,所以我希望下面的数字加到上面每个组合的实例中!)。

[
    {
        _id: 1,
       browser: 'chrome',
       ipAddress: '222.111.111.0',
       uri: 'example1.com'
    },
    {
       _id: 2,
       browser: 'chrome',
       ipAddress: '222.111.111.0',
       uri: 'example1.com'
    },
    {
       _id: 3,
       browser: 'opera',
       ipAddress: '222.0.888.0',
       uri: 'example1.com'
    },
    {
       _id: 4,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 5,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 6,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 7,
       browser: 'opera',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    }
]

我知道使用map / reduce应该可以轻松实现这一点,但我似乎无法让我对如何做到这一点感到困惑!

提前致谢。

5 个答案:

答案 0 :(得分:1)

使用lodash的另一种(更实用的)方法:

_(array).groupBy(v => ([v.browser, v.ipAddress, v.uri]))
        .map(v => _.merge(_.omit(v[0], '_id'), {count: v.length}))
        .value();

简短说明:groupBy使用browser,ipAddress和uri创建分组。在map语句中,我们删除了_id字段,并根据组中对象的数量添加计数。

答案 1 :(得分:0)

您可以使用单个reduce vanilla JavaScript 执行此操作:

&#13;
&#13;
let arr = [
    {
        _id: 1,
       browser: 'chrome',
       ipAddress: '222.111.111.0',
       uri: 'example1.com'
    },
    {
       _id: 2,
       browser: 'chrome',
       ipAddress: '222.111.111.0',
       uri: 'example1.com'
    },
    {
       _id: 3,
       browser: 'opera',
       ipAddress: '222.0.888.0',
       uri: 'example1.com'
    },
    {
       _id: 4,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 5,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 6,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 7,
       browser: 'opera',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    }
]

let result = arr.reduce((_, x) => {
  for(let i = 0; i < _.length; i++) {
    if(_[i].browser === x.browser && _[i].ipAddress === x.ipAddress && _[i].uri === x.uri) {
      _[i].count++
      return _
    }
  }
  let { _id, ...rest } = x
  return [ ..._, { ...rest, count: 1 } ]
}, [])

console.log(result)
&#13;
&#13;
&#13;

答案 2 :(得分:0)

您可以尝试这样的事情:

var data=[{_id:1,browser:"chrome",ipAddress:"222.111.111.0",uri:"example1.com"},{_id:2,browser:"chrome",ipAddress:"222.111.111.0",uri:"example1.com"},{_id:3,browser:"opera",ipAddress:"222.0.888.0",uri:"example1.com"},{_id:4,browser:"chrome",ipAddress:"222.111.222.0",uri:"sample1.com"},{_id:5,browser:"chrome",ipAddress:"222.111.222.0",uri:"sample1.com"},{_id:6,browser:"chrome",ipAddress:"222.111.222.0",uri:"sample1.com"},{_id:7,browser:"opera",ipAddress:"222.111.222.0",uri:"sample1.com"}];

function groupBy(array, keys) {
  var groups = array.reduce(function(p, c) {
    var hash = keys.map(function(k){ return c[k]; }).join("|")
    p[hash] = p[hash] || c;
    p[hash]["count"] = (p[hash]["count"] || 0) + 1
    delete p[hash]["_id"];
    return p;
  }, {});
  var result = Object.keys(groups).map(function(x){return groups[x] })
  console.log(result);
  return result
}

var keys = ["browser", "ipAddress", "uri"]
groupBy(data, keys)

答案 3 :(得分:0)

如果您愿意使用lodash(如果没有,请更好地使用),您可以执行以下操作,

var array = [
    {
        _id: 1,
       browser: 'chrome',
       ipAddress: '222.111.111.0',
       uri: 'example1.com'
    },
    {
       _id: 2,
       browser: 'chrome',
       ipAddress: '222.111.111.0',
       uri: 'example1.com'
    },
    {
       _id: 3,
       browser: 'opera',
       ipAddress: '222.0.888.0',
       uri: 'example1.com'
    },
    {
       _id: 4,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 5,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 6,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 7,
       browser: 'opera',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    }
]

var res = _.reduce(array, function(acc, elem){
  delete elem._id;
  var obj = _.find(acc, elem)
  if(obj){
    obj.count++;
  }
  else{
    elem.count = 1;
    acc.push(elem);
  }
  return acc;
}, [])

console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

答案 4 :(得分:0)

您可以使用通用的减速器生成器来实现此目的。此代码基于my previous answer to another question。您可以为其指定要分组的字段,并返回可用作减少项的计数项。

let arr = Object.freeze([
    {
        _id: 1,
       browser: 'chrome',
       ipAddress: '222.111.111.0',
       uri: 'example1.com'
    },
    {
       _id: 2,
       browser: 'chrome',
       ipAddress: '222.111.111.0',
       uri: 'example1.com'
    },
    {
       _id: 3,
       browser: 'opera',
       ipAddress: '222.0.888.0',
       uri: 'example1.com'
    },
    {
       _id: 4,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 5,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 6,
       browser: 'chrome',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    },
    {
       _id: 7,
       browser: 'opera',
       ipAddress: '222.111.222.0',
       uri: 'sample1.com'
    }
]);

const groupByReducerCount = (group) =>
  (result, row) => {
    const keygroup = group.map((v) => row[v]);
    const key = keygroup.join(':');
    if (result[key])
      result[key] ++;
    else
      result[key] = 1;
    return result;
  };


const result = arr.reduce(groupByReducerCount(['uri','browser','ipAddress']),{});

console.log(result)