Roy*_*ang 1 marklogic marklogic-9
我一直在测试将我们的一个系统迁移到Marklogic 9并使用Optics API.
我们的一个功能涉及通过member_id,member_name对索赔进行分组并获取总和和计数,所以我做了类似这样的事情:
var results = op.fromView('test', 'claims')
.groupBy(['member_id', 'member_name'], [
op.count('num_claims', 'claim_no'),
op.sum('total_amount', 'claim_amount')
])
.orderBy(op.desc('total_amount'))
.limit(200)
.result()
.toArray();
Run Code Online (Sandbox Code Playgroud)
以上工作正常.结果是形式的
[
{
member_id: 1,
member_name: 'Bob',
num_claims: 10,
total_amount: 500
},
...
]
Run Code Online (Sandbox Code Playgroud)
但是,我们还有一个"公司"字段,每个索赔都是在另一家公司下提交的.基本上,相关的视图列是claim_no,member_id,member_name,company,claim_amount
我希望能够显示一个列,其中列出了member_id/member_name已提交索赔的不同公司,以及每个公司的索赔数量.
即我希望我的结果如下:
[
{
member_id: 1,
member_name: 'Bob',
num_claims: 10,
total_amount: 500,
companies: [
{
company: 'Ajax Co',
num_claims: 8
},
{
company: 'Side Gig',
num_claims: 2
}
]
},
...
]
Run Code Online (Sandbox Code Playgroud)
我试过这样的事情:
results = results.map((member, index, array) => {
var companies = op.fromView('test', 'claims')
.where(op.eq(op.col('member_id'), member.member_id))
.groupBy('company', [
op.count('num_claims', 'claim_no')
])
.result()
.toArray();
member.companies = companies;
return member;
});
Run Code Online (Sandbox Code Playgroud)
输出似乎是正确的,但它也执行得相当慢 - 几乎一分钟(索赔文件总数约为120k)
在我们之前的ML8实现中,我们为每个成员预生成了摘要文档 - 因此检索速度相当快,不足之处在于,每当我们获得大量新数据时,所有摘要文档都必须重新生成.我希望ML9的光学API能够更容易地在运行中进行检索/分组/聚合,因此我们不必这样做.
理论上,我可以将公司添加到groupBy字段,然后根据需要合并结果查询中的行.但是这种方法的问题是我不能保证我会得到总额的前200名(就像我原来的查询一样)
所以,问题是:在合理的执行时间内有更好的方法吗?或者我应该坚持预先生成摘要文件?
如果我理解正确,您应该能够通过一组两次分组的Optic查询来实现.
查询可能类似于以下内容:
const results =
op.fromView('test', 'claims')
.groupBy(['member_id', 'company'], [
'member_name',
op.count('company_claims', 'claim_no'),
op.sum('company_amount', 'claim_amount')
])
.select(['member_id',
'member_name',
'company_claims',
'company_amount',
op.as('company_desc', op.jsonObject([
op.prop('company', op.col('company')),
op.prop('num_claims', op.col('company_claims'))
]))
])
.groupBy(['member_id'], [
'member_name',
op.sum('num_claims', 'company_claims'),
op.sum('total_amount', 'company_amount'),
op.arrayAggregate('companies', 'company_desc')
])
.orderBy(op.desc('total_amount'))
.limit(200)
.result()
.toArray();
Run Code Online (Sandbox Code Playgroud)
顺便说一下,如果在聚合列表中指定一列,则会对其进行采样.如果列具有相同的整个组的值(我假设是"member_name"的情况),则可以对其进行采样,而不是将其指定为附加的分组键.
此外,在现代JavaScript中,通常避免使用const或者let.
希望有所帮助,