MarkLogic node.js api - 按总和分组

时间:2017-06-19 03:27:10

标签: node.js marklogic

类似于我的问题:MarkLogic node.js api - group by and sort by count

我在Marklogic中有文件 name amount 。我想得到每个名字的总金额。基本上在SQL中它将是

select name, sum(amount) from table group by name

name amount 范围索引。  为了获得总和聚合,文档建议类似 valuesBuilder.fromIndexes('amount')。聚合('sum'),但这只得到所有记录的总和,而不是像我想要的每个名称

有什么建议吗?

3 个答案:

答案 0 :(得分:2)

我不认为这是一个开箱即用的群体,但你可以建立一个扩展来做到这一点。我做了一些样本文档:

declareUpdate();

for (let index=0; index < 1000; index++) {
  xdmp.documentInsert(
    '/values' + index + '.json',
    {
      "name": "val" + (xdmp.random(2) + 1),
      "amount": xdmp.random(2) + 1
    }
  )
}

我在Query Console中运行了这段代码:

'use strict';

var jsearch = require('/MarkLogic/jsearch.sjs');
var tuples = 
  jsearch.tuples(
    [
      cts.jsonPropertyReference('name'), 
      cts.jsonPropertyReference('amount', ["type=int"])
    ]
  )
    .slice(0, 1000) // get all the values
    .map({frequency: "item", names: ['name', 'count', 'frequency']})
    .result();

tuples
  .reduce(function(acc, current, index, array) {
    acc[current.name] = parseInt(current.count, 10) * current.frequency;
    return acc;
  }, {});

这让我得到了回应:

{
  "val1": 381, 
  "val2": 351, 
  "val3": 324
}

我认为这就是您正在寻找的东西。你需要的其他东西:

答案 1 :(得分:2)

作为Dave建议的替代方案,您可以在Node.js中执行类似操作,但同样,工作/代码必须由您开发。

选项1)

db.values.read(
  vb.fromIndexes('name', 'amount')
)
.result()

这里的代码会创建名称和金额的共同出现 - 然后您可以去处理这些信息。

选项2)

从索引中获取名称,然后将该信息提供给另一个获取金额并将其汇总的函数:

function getNames() {
  return db.values.read(
    vb.fromIndexes('name')
  )
  .result();
}

function getSum(names) {
  const promises = names.map(name => {
     return db.values.read(
      vb.fromIndexes('amount')
      .aggregates('sum')
      .where(vb.parsedFrom(`name:${name}`,
             vb.parseBindings(vb.value('name', vb.bind('name')))
    ))).result();
  });
  return Promise.all(promises);
};

getNames()
.then(response => {
  const names = response['values-response'].tuple.map(name => name['distinct-value'].toString());
  console.log(names); //this will hold all the names
  return getSum(names);
})
.then(response => {
  const sums = response.map(r => {
    return r['values-response']['aggregate-result'][0];
  }).map(s => s._value);
  console.log(sums); //this will hold all the sums
})
.catch(error => console.log(error));

选项3)

Dave建议 - 创建SJS扩展,并从Node.js调用它

答案 2 :(得分:1)

来自Tamas和Dave的好建议的一个脚注 - 在MarkLogic 9中,您可以使用类似于以下示例的方式使用Optic API(在本例中,使用服务器端JavaScript):

'use strict';
const op = require('/MarkLogic/optic');

const employees = op.fromView(null, 'employees');
const expenses  = op.fromView(null, 'expenses');
employees
   .joinInner(expenses, op.on(
       employees.col('EmployeeID'), expenses.col('EmployeeID')
       ))
   .groupBy('LastName', op.sum('Total', 'Amount'))
   .orderBy('Total')
   .where(op.lt(199, op.col('Total')))
   .result();