TLDR;如果字段是静态的并且您可以轻松地枚举它们,那么您的两个解决方案几乎都是正确的(请参阅下文以了解它们为什么不正确。)这是正确的方法:
result = [
mapped |
original := data[_]
mapped := {"some": original["some"], "another": original.another}
]
一个更优雅的选择是定义要包含或排除的字段,就像在@eephillip 的示例中一样。例如:
result = [
mapped |
original := data[_]
mapped := {k: v |
some k
v := original[k]
not exclude[k]}
]
exclude = {"dont", "dont2"} # defines a SET of keys to exclude
当然,您可以通过使内部理解调用实现其他过滤器的函数来进一步概括它。
这是一个交互式示例:https ://play.openpolicyagent.org/p/P6wPd3rudJ
关于原始解决方案的两个注释。
1.result1
没有data
正确迭代
{d |
d := {
"some": data[_].some, # problem: _ is a different variable in each expression
"another": data[_].another
}
}
从概念上讲,每次出现_
都是唯一的变量。如果显式声明变量,问题就更明显了:
# note: this is still wrong
{d |
some i, j
d := {
"some": data[i]["some"],
"another": data[j].another
}
}
如果你运行它,你会发现它产生了一个交叉产品(这不是你想要的)。您希望从同一个对象中选择“一些”和“另一个”字段,如下所示:
{d |
some i
d := {
"some": data[i]["some"],
"another": data[i].another
}
}
当然,想出唯一的变量名可能会很痛苦,所以你可以使用_
. 只是不要将多个_
变量误认为是指相同的值。我们可以重写语句来使用_
如下:
{d |
obj := data[_]
d := {
"some": obj["some"],
"another": obj.another
}
}
result2
接近但可以分配多个值(应该避免)
result2 = cleaned {
d := data[_]
cleaned := { # problem: there could be multiple values for 'cleaned'
"some": d["some"],
"another": d.another
}
}
如果满足中的陈述,则NAME = VALUE { BODY }
分配VALUE
给形式的规则。如果您省略,即您编写,则默认为(始终满足。)NAME
BODY
BODY
NAME = VALUE
BODY
true
在你上面的例子中:
NAME
是result2
VALUE
是cleaned
BODY
是d := data[_]; cleaned := {...}
在 Rego 中,我们将这些规则称为“完整规则”。完整的规则只是将单个值分配给变量的 IF-THEN 语句。“IF”部分是规则主体,“THEN”部分是分配。您应该避免编写可能将多个值分配给同一变量的规则,因为这可能会导致评估时间错误。例如:
# do not do this
result = v {
v := data[_] # if 'data' is [1,2,3] then what is the value of 'result'? Hint: There is more than one answer.
}
如果要为变量分配多个值,则可以定义“部分规则”例如:
result[v] { # result is a SET.
v := data[_]
}