学习

使用 JSON 管理文档数据

Simon Prickett
作者
Simon Prickett, Redis 首席开发者倡导者

我们使用 Redis 的内置 Hash 数据类型来表示我们的用户和位置实体。Hash 非常适合此目的,但它们有限制,因为它们只能包含扁平的名称/值对。对于我们的位置,我们希望以更结构化的方式存储额外的详细信息。

以下是我们希望存储有关位置的额外数据的示例

{
  "id": 121,
  "hours": [
    { "day": "Monday", "hours": "6-7" },
    { "day": "Tuesday", "hours": "6-7" },
    { "day": "Wednesday", "hours": "7-8" },
    { "day": "Thursday", "hours": "6-9" },
    { "day": "Friday", "hours": "8-5" },
    { "day": "Saturday", "hours": "9-6" },
    { "day": "Sunday", "hours": "6-4" }
  ],
  "socials": [
    {
      "instagram": "theginclub",
      "facebook": "theginclub",
      "twitter": "theginclub"
    }
  ],
  "website": "www.theginclub.com",
  "description": "Lorem ipsum...",
  "phone": "(318) 251-0608"
}

我们可以将这些数据作为序列化 JSON 存储在 Redis 字符串中,但这样我们的应用程序每次想要读取部分数据时都必须检索并解析整个文档。我们也必须这样做才能更新它。此外,使用这种方法,更新操作不是原子的,第二个客户端可以在我们的应用程序代码中对给定键存储的 JSON 进行更新,而我们正在对其进行更改。然后,当我们将 JSON 的版本序列化回 Redis 字符串时,另一个客户端的更改将丢失。

Redis Stack 为 Redis 添加了一种新的 JSON 数据类型,以及用于在 Redis 服务器上原子地选择和更新 JSON 文档中的单个元素的查询语法。这使我们的应用程序代码更简单、更高效、更可靠。

编码练习#

在本练习中,您将完成用于获取表示给定日期位置开放时间的对象的 API 路由的代码。打开文件 src/routes/location_routes.js,找到路由 /location/:locationId/hours/:day。入门代码如下

// EXERCISE: Get opening hours for a given day.
router.get(
  '/location/:locationId/hours/:day',
  [
    param('locationId').isInt({ min: 1 }),
    param('day').isInt({ min: 0, max: 6 }),
    apiErrorReporter,
  ],
  async (req, res) => {
    /* eslint-disable no-unused-vars */
    const { locationId, day } = req.params;
    /* eslint-enable */
    const locationDetailsKey = redis.getKeyName('locationdetails', locationId);

    // TODO: Get the opening hours for a given day from
    // the JSON stored at the key held in locationDetailsKey.
    // You will need to provide the correct JSON path to the hours
    // array and return the element held in the position specified by
    // the day variable.  Make sure Redis JSON returns only the day
    // requested!
    const jsonPath = 'TODO';

    /* eslint-enable no-unused-vars */
    const hoursForDay = JSON.parse(
      await redisClient.call('JSON.GET', locationDetailsKey, jsonPath),
    );
    /* eslint-disable */

    // If null response, return empty object.
    res.status(200).json(hoursForDay || {});
  },
);

您需要更新代码以提供正确的 JSON 路径,用 JSON 路径表达式替换“TODO”值。

查看存储在键 ncc:locationdetails:121 的 JSON,我们看到开放时间存储在一个名为 hours 的字段中的对象数组中,其中第 0 天是星期一,第 6 天是星期日

因此,您需要一个 JSON 路径查询,根据存储在变量 day 中的值从 hours 数组中获取正确的元素。

如果您使用的是 redis-cli,可以使用以下命令查看 JSON 文档的结构

json.get ncc:locationdetails:121 .

确保您的查询只返回请求的日期,这样您就不必编写 Node.js 代码来过滤从 Redis 返回的值。使用 JSON 路径语法页面 来帮助您制定正确的查询。

要测试您的代码,请使用以下命令启动服务器

$ npm run dev

请记住,这将允许您编辑代码并在不重启服务器的情况下尝试更改。

如果您的代码中包含正确的 JSON 路径,访问 https://localhost:80801/api/location/121/hours/2 应该返回

{
  "day": "Wednesday",
  "hours": "7-8"
}

不要忘记,如果您有任何问题或需要帮助,可以访问 Discord.

外部资源#

详细了解 JSON,请访问 https://redis.ac.cn/docs/stack/json/.

在此视频中,Justin 使用一个有趣的炸玉米饼车示例介绍 JSON!