为什么以及何时需要展平JSON对象?

时间:2014-07-18 20:35:41

标签: javascript json jsonobject flatten

我很惊讶,之前没有人问过这个问题。

查看Json对象文档和快速谷歌搜索并没有产生令人满意的结果。

它有什么优势?它是如何工作的?


编辑:要说清楚,请看一下这个展平/不展平的例子。

Fastest way to flatten / un-flatten nested JSON objects

谢谢。

3 个答案:

答案 0 :(得分:5)

这是一个简单的场景:在Web应用程序中,您有一个HTTP POST,它正在更新复杂的关系对象。

POST
update=1
&user.id=12345
&user.email=testmail@domain.tld
&user.profile.name=Mr. Test
&user.profile.age=42
&user.profile.friend.0.email=tom@domain.tld
&user.profile.friend.1.email=sally@domain.tld
&user.profile.friend.2.email=bob@domain.tld
&user.profile.skill.0.id=100
&user.profile.skill.0.name=javascript
&user.profile.skill.1.id=200
&user.profile.skill.1.name=piano

一切都已经处于扁平结构中,为什么不进行简单的一对一绑定?如果您有一个需要强制执行的约束或安全要求列表,则可以通过直接搜索已排序的密钥列表来验证它们。

平面结构更易于人们理解和使用,甚至可以与数据库反规范化进行交叉。它还允许以可读但更冗长的方式实现特定于上下文的安全性和约束。

当完整显示用户的视图时,您可能希望隐藏用户的技能列表的主键ID的显示。

"user.profile.skill.#.id": { hidden: true, readonly: true }

但是当直接查看某项技能(可能以管理员身份编辑)时,您可能希望看到该ID。

"skill.id": { readonly: true }

如果您正在编写以用户为中心/自助服务类型的CMS应用程序,那么您可以获得更多用户,并且能够使用简单的平面模型(底层嵌套关系模型的扁平抽象)进行贡献。只使用嵌套模型。

TLDR:Flat比嵌套更容易阅读。程序员可以处理嵌套模式,递归解析和处理;最终用户和管理员通常更喜欢将这部分抽象出去。

答案 1 :(得分:4)

在许多情况下,您会获得由某些库自动构建的JSON文本。在整个编程语言中,有许多库可以构建JSON文本(一个example is here)。

每当库添加一些额外的对象或数组包装时,您可能希望摆脱它们,可能是因为您将JSON发送到服务器并且您的代码崩溃,因为它需要原始值而不是对象(或数组) 。或者,如果您的JSON是服务器响应,那么您不希望生成的Javascript代码在对象/数组之间或对象/数组之间不同。在所有这些情况下,展平是有帮助的,因为它可以节省您的时间。您必须实现较小的if / elses,并且可以可靠地期望您的数据结构尽可能平坦。

改进上述方案代码的另一种方法是以最强大的方式编写代码,这样就无法通过多余的包装来崩溃代码。所以总是期待一些包装并获得它的内容。然后,不需要压扁。

你知道,这取决于构建JSON的内容以及解析它的内容。建筑可能超出了您的范围。

这也导致数据模型问题。我曾经使用过需要以不同的方式安静地解析的XML代码,如果有一些XY的0个条目,或者某些XY有> 0个条目。拥有一个允许有一些XY的0或更多条目的包装将使生活更容易。这些是数据模型的定义。

在JSON代表我手动合并的对象结构的所有情况下,我希望不要更改。如此扁平化我已经详细设计的东西会令人不安。标准操作到目前为止我看到它们不需要展平(例如JSON.stringify()json_encode()等。

答案 2 :(得分:3)

此时我意识到这是一个 5 年前的问题,但我想,我会添加我的想法,以防有人遇到类似的用例并发现它很有用。

您想要展平 JSON 对象的用例之一是通过正则表达式 (RegEx) 字符串插值进行动态模板绑定。那不就是一口??吗?它简单地转换为“模板填充没有硬编码的字符串”

好的,想象一个场景,你有一个像这样的电子邮件模板字符串:

Hello {{firstName}},

It is amazing you chose to join our site. We are happy to have you on board. 
To get started, we would really love it if you can confirm your email address
by clicking on the link: {{confirm_url}}.

Welcome aboard

The Team!

鉴于内存中的以下 JSON 对象:

{
   "user" : {
               "prefix"      : "Dr.",
               "firstName"   : "Awah",
               "lastName"    : "Teh",
               "email"       : "awah@superduperubercoolsite.com",
               "address"     : {
                                  "street": "100 Main St",
                                  "city"  : "PleasantVille",
                                  "state" : "NY",
                                  "phone" : "+1-212-555-1212"
                               }
            },
   "meta" : {
               "confirm_url" : "http://superduperubercoolsite.com/confirm/ABC123"
            }
}

像这样执行正则表达式替换似乎超级简单(假设我们的电子邮件模板字符串存储在名为 template 的变量中,而 json 对象存储在名为 templateData 的变量中:

template = template.replace(new RegExp('{{firstName}}', 'g'), templateData.user.firstName);
template = template.replace(new RegExp('{{confirm_url}}', 'g'), templateData.meta.confirm_url);

容易吧? --> 其实是的!这封电子邮件有 10 个模板化字段如何,或者您想将模板与代码分离,将其存储在一个单独的系统中,例如 SendGrid,您的营销主管可以在其中访问模板并对复制语言进行更改,而无需不得不打电话给工程部门的人来更改代码、测试代码并重新部署到生产环境中(真麻烦)。

这正是 JSON 扁平化的关键所在!

现在有很多方法可以展平 JSON,我写的 attached a link to a codepen 具有展平 JSON 的逻辑(实际上,我在方法 flattenJSONIntoKVP 和 {{1} } 看看它们!)。

也就是说,还有其他实现,值得记住的是,这篇文章的重点是讨论 为什么 JSON 扁平化可能有用,而不是 如何强>.

继续前进!假设您将上面的 JSON(使用我的导致键值对的实现)扁平化为如下所示:

flattenJSONIntoRAW

现在,我的朋友,你在用 GAS 做饭!

为什么,因为现在您可以使用来自 JSON 对象的值动态 [ { "key": "user.prefix", "value": "Dr."}, { "key": "user.firstName", "value": "Awah"}, { "key": "user.lastName", "value": "Teh"}, { "key": "user.email", "value": "awah@superduperubercoolsite.com"}, { "key": "user.address.street", "value": "100 Main St"}, { "key": "user.address.city", "value": "{PleasantVille"}, { "key": "user.address.state", "value": "NY"}, { "key": "user.address.phone", "value": "+1-212-555-1212"}, { "key": "meta.confirm_url", "value": "http://superduperubercoolsite.com/confirm/ABC123"}, ] 模板字符串,而不必过多担心 JSON 的结构(如果它因应用程序的发展而发生变化,您不必还记得来这里并更改此插值代码 - 您只需要更新电子邮件模板本身,请注意,在 SendGrid [每个示例] 上)。

那你说怎么做?:简单,迭代。让我们假设从上面扁平化存储在一个名为 interpolate 的变量中:

flatJSON

就是这样,一行代码可以替换 10 个,甚至数百个甚至数千个(好吧……也许不是数千个,但你明白了。

哦!差点忘了,我们需要更新我们的模板字符串。

注意现在,在我们新的模板化字符串中,我们可以使用一个有点 FQDN 样式的变量来映射回我们的原始 JSON(理想情况下,如果 SendGrid 支持在其模板占位符中使用点,这看起来非常好,但可惜,不能总是赢得一切!?。


///Notice how I use Javascripts native string interpolation to create my RegExp

///Also note that I am replacing the dot (.) in my flattened JSON variable names with a double underscore (__), I only do this because my intended target is SendGrid, and I don't believe it likes dots in its template placeholders.
flatJSON.forEach(kvp=>template = template.replace(new RegExp(`{{${kvp.key.replace(/\./g, '__'}}}`, 'g'), kvp.value));

等等!

就这样,我们今天在这里取得了一些成绩;我们有:

  1. 回答了扁平化 JSON 对象的原因
  2. 我们用 codepen example
  3. 深入研究了方法
  4. 我们甚至概述了一个用例,在该用例中,利用 JSON 扁平化可以帮助您编写持久的动态代码,该代码随着您的底层对象结构的变化而发展——并且不需要您利用大的丑陋的 {{1 }} 方法(我们可以在另一篇文章中讨论大坏丑评估)。