如何为嵌套JSON编写json-rules-engine规则?事件未触发排查
问题分析
你的代码事件未触发,原因是facts.claims是一个数组,而当前规则中直接对claims这个数组对象使用$.claimantName路径查询,数组本身并没有claimantName属性,因此条件永远不成立。
解决方案
要匹配数组中的嵌套对象,有两种常用方式:利用JSONPath语法,或者自定义fact函数。以下分别给出实现:
方式1:使用JSONPath语法匹配数组元素
json-rules-engine的path参数支持JSONPath,你可以通过JSONPath查询数组中是否存在符合条件的元素,再结合truthy操作符判断结果是否非空:
const { Engine } = require('json-rules-engine') function scenario1() { let engine = new Engine() engine.addRule({ conditions: { any: [ { fact: "claims", // JSONPath查询:筛选所有claimantName为john的数组元素 path: "$[?(@.claimantName == 'john')]", // 判断结果数组是否非空(存在匹配元素) operator: "truthy", value: true } ] }, event: { type: "claim", params: { message: "claim found" } } }) let facts = { claims: [ { claimantName: "john", dob: "1985-01-01", exposures: [ { id:"1", type:"liability", value:"$2500", xyv:[{type:"abc"},{type:"gfd"}] }, { id:"2", type:"healthcare", value:"$500", xyv:[{type:"bbb"}] } ], vehicles: [{id:1, name:"ford"}, {id:"2", name:"jeep"}] } ] } engine.run(facts) .then(({ events }) => { events.map(event => console.log(event.params.message)) }) console.log("done") } scenario1()
方式2:自定义Fact函数(更灵活,适合复杂嵌套条件)
如果后续需要更复杂的判断(比如同时检查xyv.type),自定义fact函数会更可控。你可以编写一个fact来遍历数组,返回是否存在符合所有条件的元素:
const { Engine } = require('json-rules-engine') function scenario1() { let engine = new Engine() // 自定义fact:检查是否存在claimantName为john的claim engine.addFact("hasJohnClaim", (params, almanac) => { return almanac.factValue("claims").then(claims => { // 遍历claims数组,判断是否存在匹配元素 return claims.some(claim => claim.claimantName === "john") }) }) engine.addRule({ conditions: { any: [ { fact: "hasJohnClaim", operator: "equal", value: true } ] }, event: { type: "claim", params: { message: "claim found" } } }) let facts = { claims: [ { claimantName: "john", dob: "1985-01-01", exposures: [ { id:"1", type:"liability", value:"$2500", xyv:[{type:"abc"},{type:"gfd"}] }, { id:"2", type:"healthcare", value:"$500", xyv:[{type:"bbb"}] } ], vehicles: [{id:1, name:"ford"}, {id:"2", name:"jeep"}] } ] } engine.run(facts) .then(({ events }) => { events.map(event => console.log(event.params.message)) }) console.log("done") } scenario1()
扩展:添加xyv.type的条件
如果需要同时检查claimantName为john且其exposures中存在xyv.type为abc的元素,可以修改自定义fact函数:
engine.addFact("hasMatchingClaim", (params, almanac) => { return almanac.factValue("claims").then(claims => { return claims.some(claim => { // 先判断claimantName是否匹配 if (claim.claimantName !== "john") return false // 再判断exposures中的xyv.type是否存在目标值 return claim.exposures.some(exposure => { return exposure.xyv.some(xyv => xyv.type === "abc") }) }) }) })
然后在规则中使用这个fact即可:
engine.addRule({ conditions: { any: [ { fact: "hasMatchingClaim", operator: "equal", value: true } ] }, event: { type: "claim", params: { message: "claim with john and xyv.type=abc found" } } })
内容的提问来源于stack exchange,提问作者HHH
相关产品推荐
相关产品推荐

