MarkLogic中实现按字段分组,保留每组最大版本值的JSON文档服务端查询
服务端实现JSON文档分组并取每组最大version的方案
针对你需要先筛选JSON文档、按id分组、再返回每组version最大值对应文档的需求,以下是两种基于MarkLogic服务端的实现方案,可避免在Java端处理大量数据的传输开销:
方案一:通过ServerEvaluationCall调用XQuery实现
利用XQuery的分组语法,直接在服务端完成筛选、分组和取最大值的逻辑:
XQuery核心逻辑
xquery version "1.0-ml"; for $doc in cts:search(fn:doc(), cts:json-property-value-query("typeId", "CAR")) let $id := $doc/id let $version := $doc/version group by $id let $max-version-doc := fn:head(fn:sort($doc, (), function($d) { -$d/version })) return $max-version-doc
- 先通过
cts:search筛选出typeId为CAR的文档 - 按
id字段分组,每组内将文档按version倒序排序,取第一个即为该组version最大的文档
Java端调用代码
import com.marklogic.client.DatabaseClient; import com.marklogic.client.eval.ServerEvaluationCall; import com.marklogic.client.io.JacksonHandle; import com.fasterxml.jackson.databind.JsonNode; // 假设已初始化DatabaseClient实例client ServerEvaluationCall eval = client.newServerEval(); String xquery = "xquery version \"1.0-ml\"; " + "for $doc in cts:search(fn:doc(), cts:json-property-value-query(\"typeId\", \"CAR\")) " + "let $id := $doc/id " + "let $version := $doc/version " + "group by $id " + "let $max-version-doc := fn:head(fn:sort($doc, (), function($d) { -$d/version })) " + "return $max-version-doc"; eval.xquery(xquery); JacksonHandle resultsHandle = new JacksonHandle(); eval.eval(resultsHandle); JsonNode results = resultsHandle.get(); // results即为包含目标文档的JSON数组
方案二:通过ServerEvaluationCall调用JavaScript实现
用JavaScript的对象分组逻辑,同样在服务端完成处理:
JavaScript核心逻辑
const docs = cts.search(cts.jsonPropertyValueQuery("typeId", "CAR")).toArray(); const groups = {}; for (const doc of docs) { const id = doc.id; // 若当前id未记录,或当前文档version更大,则更新为当前文档 if (!groups[id] || doc.version > groups[id].version) { groups[id] = doc; } } // 返回所有分组的最大version文档 return Object.values(groups);
Java端调用代码
import com.marklogic.client.DatabaseClient; import com.marklogic.client.eval.ServerEvaluationCall; import com.marklogic.client.io.JacksonHandle; import com.fasterxml.jackson.databind.JsonNode; // 假设已初始化DatabaseClient实例client ServerEvaluationCall eval = client.newServerEval(); String jsCode = "const docs = cts.search(cts.jsonPropertyValueQuery(\"typeId\", \"CAR\")).toArray(); " + "const groups = {}; " + "for (const doc of docs) { " + " const id = doc.id; " + " if (!groups[id] || doc.version > groups[id].version) { " + " groups[id] = doc; " + " } " + "} " + "return Object.values(groups);"; eval.javascript(jsCode); JacksonHandle resultsHandle = new JacksonHandle(); eval.eval(resultsHandle); JsonNode results = resultsHandle.get(); // results即为包含目标文档的JSON数组
关于JSearch.reduce的局限性
JSearch的reduce是全局聚合操作,无法实现先分组再聚合的逻辑,因此只能返回全局version最大的单份文档,无法满足按id分组取每组最大值的需求,所以需要采用上述服务端分组的方案。
内容的提问来源于stack exchange,提问作者GalaxyTile
相关产品推荐
相关产品推荐

