将点符号 JSON 转换为弹性搜索深度嵌套查询 JSON,使用 bodybuilder.js?
Convert dot-notation JSON into elastic search deeply nested query JSON, with bodybuilder.js?
如果我有一个平面数据结构,它使用点符号来表示深度。看起来像这样:
{
"key1": "name1",
"key2.subKey.finalKey": "name2"
}
我正在使用它来创建我的查询:
let query = _.reduce(jsonQuery, (queryBody, queryValue, queryName)=>{
return queryBody.query("term", "queryName", "queryValue")
}, bodybuilder())
我已经简化了,但这绝不能处理伪嵌套数据。
我有一个函数可以将点符号转换为嵌套。
以下是健美运动员建议的嵌套结构:
bodybuilder()
.query('nested', 'path', 'obj1', (q) => {
return q.query('match', 'obj1.color', 'blue')
})
.build()
这将导致以下查询结构:
{
"query": {
"nested": {
"path": "obj1",
"query": {
"match": {
"obj1.color": "blue"
}
}
}
}
}
所以在我的多嵌套版本中,我希望得到:
{
"query": {
"nested": {
"path": "key2",
"query": {
"nested": {
"field": "key2.subkey",
"query": {
"match": {
"key2.subkey.finalKey": "name2"
}
}
}
}
}
}
}
我正在努力思考如何根据上面的伪嵌套结构动态地执行此操作。递归的东西,但我不确定如何制作粗箭头函数。
这是我目前最接近的:
const nestQuery = (chain, value, method="match") =>{
return q => q.query(method, chain, value)
}
const pathMapping = 'key2.subkey.finalKey';
const fooMapping = pathMapping.split('.').map((part, index, splitPath) =>{
return splitPath.slice(0, index+1).join('.');
})
const body = bodybuilder();
fooMapping.reduce((nestedBody, subPath, index, allPaths)=>{
const next = allPaths[index+1]
return nestedBody.query('nested', subPath,
nestQuery(next, 'blue'))
}, body)
console.log(body.build())
<script src="https://rawgit.com/danpaz/bodybuilder/master/browser/bodybuilder.min.js"></script>
但是当我需要一个嵌套查询时,这会为您提供三个单独的查询。
您使用 reduce
的直觉确实在朝着正确的方向发展。但是,如果从最内层的查询(其参数看起来与其他 query
调用完全不同)开始,从相反的方向减少,就会容易得多,向后工作。这样你就可以将之前构建的回调包装到另一个回调函数中,从内到外工作:
function buildQuery(path, value) {
// Build one part less, as the last one needs a different query syntax anyway
// ... and we have its value already in `path`:
const keys = path.split('.').slice(0, -1).map((part, index, splitPath) => {
return splitPath.slice(0, index+1).join('.');
});
// Use reduceRight to build the query from the inside out.
const f = keys.reduceRight( (f, key) => {
return q => q.query("nested", "path", key, f); // f is result of previous iteration
}, q => q.query("match", path, value)); // Initial value is the innermost query
return f(bodybuilder()).build();
}
// Demo
console.log(buildQuery("key2.subkey.finalKey", "name2"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://rawgit.com/danpaz/bodybuilder/master/browser/bodybuilder.min.js"></script>
如果我有一个平面数据结构,它使用点符号来表示深度。看起来像这样:
{
"key1": "name1",
"key2.subKey.finalKey": "name2"
}
我正在使用它来创建我的查询:
let query = _.reduce(jsonQuery, (queryBody, queryValue, queryName)=>{
return queryBody.query("term", "queryName", "queryValue")
}, bodybuilder())
我已经简化了,但这绝不能处理伪嵌套数据。
我有一个函数可以将点符号转换为嵌套。
以下是健美运动员建议的嵌套结构:
bodybuilder()
.query('nested', 'path', 'obj1', (q) => {
return q.query('match', 'obj1.color', 'blue')
})
.build()
这将导致以下查询结构:
{
"query": {
"nested": {
"path": "obj1",
"query": {
"match": {
"obj1.color": "blue"
}
}
}
}
}
所以在我的多嵌套版本中,我希望得到:
{
"query": {
"nested": {
"path": "key2",
"query": {
"nested": {
"field": "key2.subkey",
"query": {
"match": {
"key2.subkey.finalKey": "name2"
}
}
}
}
}
}
}
我正在努力思考如何根据上面的伪嵌套结构动态地执行此操作。递归的东西,但我不确定如何制作粗箭头函数。
这是我目前最接近的:
const nestQuery = (chain, value, method="match") =>{
return q => q.query(method, chain, value)
}
const pathMapping = 'key2.subkey.finalKey';
const fooMapping = pathMapping.split('.').map((part, index, splitPath) =>{
return splitPath.slice(0, index+1).join('.');
})
const body = bodybuilder();
fooMapping.reduce((nestedBody, subPath, index, allPaths)=>{
const next = allPaths[index+1]
return nestedBody.query('nested', subPath,
nestQuery(next, 'blue'))
}, body)
console.log(body.build())
<script src="https://rawgit.com/danpaz/bodybuilder/master/browser/bodybuilder.min.js"></script>
但是当我需要一个嵌套查询时,这会为您提供三个单独的查询。
您使用 reduce
的直觉确实在朝着正确的方向发展。但是,如果从最内层的查询(其参数看起来与其他 query
调用完全不同)开始,从相反的方向减少,就会容易得多,向后工作。这样你就可以将之前构建的回调包装到另一个回调函数中,从内到外工作:
function buildQuery(path, value) {
// Build one part less, as the last one needs a different query syntax anyway
// ... and we have its value already in `path`:
const keys = path.split('.').slice(0, -1).map((part, index, splitPath) => {
return splitPath.slice(0, index+1).join('.');
});
// Use reduceRight to build the query from the inside out.
const f = keys.reduceRight( (f, key) => {
return q => q.query("nested", "path", key, f); // f is result of previous iteration
}, q => q.query("match", path, value)); // Initial value is the innermost query
return f(bodybuilder()).build();
}
// Demo
console.log(buildQuery("key2.subkey.finalKey", "name2"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://rawgit.com/danpaz/bodybuilder/master/browser/bodybuilder.min.js"></script>