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
}
}
如果满足BODY 中的语句,则NAME = VALUE { BODY } 形式的规则将VALUE 分配给NAME。如果你省略BODY,即你写NAME = VALUE,那么BODY默认为true(总是满足的)
在你上面的例子中:
-
NAME 是 result2
-
VALUE 是 cleaned
-
BODY 是 d := data[_]; cleaned := {...}
在 Rego 中,我们将这些规则称为 "complete rules"。完整的规则只是将单个值分配给变量的 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.
}
如果你想为一个变量分配多个值,那么你可以定义一个"partial rule" 例如:
result[v] { # result is a SET.
v := data[_]
}