点 Redis 8 已发布——它是开源的

了解更多

Redis OM for Node.JS 有什么新进展?

Redis OM for Node.js 仍处于早期阶段,但我们正在取得很大进展。以下是我们最新版本中添加的内容以及未来的方向。

几个月前,我发布了 Redis OM for Node.js 的预览版。当时我对此感到很满意。它做到了它应有的功能,至少在开发周期的早期是这样。 

让我特别高兴的一点是用于搜索的流式接口。你知道,就是这个东西

const albums = await repository.search()
  .where('artist').equals('Mushroomhead')
  .and('title').matches('butterfly')
  .and('year').is.greaterThan(2000)
    .return.all()

但最棒的部分——也是我最满意的地方——是 Redis OM for Node.js 在开发者社区中获得的广泛采用和使用。你们中的许多人通过我们的 Discord 服务器 提供了许多有用且可行的反馈。此外,你们还修复了错误,甚至在我 GitHub 上相当粗略定义的问题中提交了完整的功能。衷心感谢你们的帮助。

我已经采纳了你们的反馈、拉取请求和贡献。在这篇文章中,我总结了我们——这里的“我们”是指“你和我”——对 Redis OM 所做的一些改变。

更容易地创建 Entity

早期,互联网上的某个人 建议 .createEntity 调用应该接受该 Entity 的初始值。我认为这是一个很棒的主意,并在 Redis OM 中采用了它。

所以曾经有点冗长的代码

const album = albumRepository.createEntity()
album.artist = "Mushroomhead"
album.title = "The Righteous & The Butterfly"
album.year = 2014
album.genres = [ 'metal' ]
album.outOfPublication = true

const id = await albumRepository.save(album)

变得简洁多了

const album = albumRepository.createEntity({
  artist: "Mushroomhead",
  title: "The Righteous & The Butterfly",
  year: 2014,
  genres: [ 'metal' ],
  outOfPublication: true
})

const id = await albumRepository.save(album)

我甚至添加了一个 .createAndSave 方法,以消除对 .save 的调用,因为这是一种非常常见的模式

const album = await albumRepository.createAndSave({
  artist: "Mushroomhead",
  title: "The Righteous & The Butterfly",
  year: 2014,
  genres: [ 'metal' ],
  outOfPublication: true
})

谢谢这个建议。这是一个不错的建议。

设置 Entity 过期

Redis 是一个很棒的数据库,也是一个非常好的缓存。你们中的许多人建议我们需要一种创建过期 Entity 的方法。 

有求必应

const ttlInSeconds = 12 * 60 * 60  // 12 hours
await albumRepository.expire('01FVDN241NGTPHSAV0DFDBXC90', ttlInSeconds)

不确定你为什么会想让一张 Mushroomhead 专辑过期,但是 *萝卜青菜,各有所爱*。

点和日期类型

没人要求这些,但我还是想要!RediSearch 对 GEO 类型的地理位置有很好的支持,日期也用于各种应用程序。所以我分别添加了 pointdate 类型。

const studioSchema = new Studio(Studio, {
  name: { type: 'string' },
  city: { type: 'string' },
  state: { type: 'string' },
  location: { type: 'point' },
  established: { type: 'date' }
})

当然,它们与流式搜索接口完美兼容

const studios = await studioRepository.search()
  .where('established').after(date)
  .return.all()

const studios = await studioRepository.search()
  .where('location').inRadius(
    circle => circle.origin(-81.7758995, 41.4976393).radius(50).miles)
  .return.all()

更好地集成 Node Redis

可能我在 Redis OM for Node.js 中最喜欢的改变是它与 Node Redis 的工作方式。在预览版中,你可以 .open 一个在幕后使用 Node Redis 的客户端

const client = new Client()
await client.open('redis://localhost:6379')

现在,你可以 .use 一个来自 Node Redis 的现有连接

import { createClient } from 'redis'

const redis = createClient('redis://localhost:6379')
await redis.connect()
const client = await new Client().use(redis)

这让你能够以各种方式连接到 Redis,而不仅仅是使用简单的连接字符串。我还更改了 .open 和 .use 以返回 Client,从而实现简洁的一行代码操作

const client = await new Client().open('redis://localhost:6379')

一些破坏性变更

没有哪个预览版是完美的;这就是它为何是预览版的原因。我在观察人们使用 Redis OM for Node.js 时犯的错误中学到了很多。这些错误源于对 Redis OM 接口某些部分的误解。这些部分需要改进,因为我没有充分思考过它们。这些改进导致了一些重要但具有破坏性的变更。

重命名一些类型

我注意到很多人在使用 string 类型时,分不清 RediSearch 中的 TEXT 和 TAG。因此,我将 string 类型拆分为两种类型:stringtext,明确了这种区别。

我还了解到,array 类型只能是字符串数组这一点并不清楚。我将其更改为 string[]

let albumSchema = new Schema(Album, {
  artist: { type: 'string' },
  title: { type: 'text' },
  year: { type: 'number' },
  genres: { type: 'string[]' },
  outOfPublication: { type: 'boolean' }
})

JSON 是默认值

几乎所有使用 Redis OM 的人都同时使用了 RediSearch 和 RedisJSON。他们选择将文档存储为 JSON 文档。但在预览版中,Redis OM 使用 Hashes 作为默认存储机制。

这导致每个人都必须明确告诉 Redis OM 使用 JSON

let albumSchema = new Schema(Album, {
  artist: { type: 'string' },
  title: { type: 'string' },
  year: { type: 'number' },
  genres: { type: 'string[]' },
  outOfPublication: { type: 'boolean' }
}, {
  dataStructure: 'JSON'
})

为了避免这一步,我更改了默认设置

let albumSchema = new Schema(Album, {
  artist: { type: 'string' },
  title: { type: 'string' },
  year: { type: 'number' },
  genres: { type: 'string[]' },
  outOfPublication: { type: 'boolean' }
})

这项改变并没有真正影响太多开发者,因为你们反正都在使用 JSON。但知道现在可以少写一点代码感觉也不错!

软件永无止境

当然,软件永远不会完成。我想添加到 Redis OM 的东西可能比我有时间实现的多。以下是我正在考虑在未来版本中添加的一些功能:

  • 可嵌入 Entity:这无疑是呼声最高的功能。目前,Entity 是扁平的。你无法使用 Redis OM 在 JSON 中创建嵌套对象。在你阅读这篇博文时,我正在进行这项工作。敬请期待。
  • 自带键:这是另一个流行的请求。Redis OM 在创建 Entity 时生成一个键,称之为 Entity ID。但你通常已经有一个希望使用的主键。我可能会在完成可嵌入 Entity 后着手解决这个问题。
  • 装饰器:我想使用装饰器,以便 Schema 中的信息可以直接通过注解来表示。TypeScript 拥有它们,虽然它们仍然是“实验性”的,但如果装饰器对 Next.js 来说足够好,那对我来说可能也足够了。也许 JavaScript 很快也会拥有它们。这可能是 RedisOM for Node.js 的一个 2.0 版本功能。

一些有用的资源

如果你刚刚开始使用 Redis OM,我也一直在准备一些有用的内容

  • 我用 Express 和 Redis OM 编写了一个简单的示例 API。把它看作是入门代码。Fork 它,做出你的修改,然后开始吧。
  • 我制作了一个视频工作坊,引导你使用 Express 和 Redis OM 构建 API。本质上,这就是前面提到的入门代码,但它一步步向你展示如何构建 API。
  • 所有新功能和旧功能都记录在README中。如果你想知道如何做某件事,里面可能就有。
  • 如果你遇到困难,我经常在Redis Discord服务器上。可能比健康的时间都多。好好利用这一点!
  • 我和我的一些同事在Twitch上直播各种内容——包括很多关于 Redis OM 和 Redis Stack 的东西。在那里观看我们吧。

致谢

那么,这就是 Redis OM for Node.js 最新进展的总结如何?Redis OM 之所以能取得今天的成就,是因为社区中各位朋友的帮助。所以,我想用一个衷心的“谢谢”来结束,感谢那些……嗯……提供了帮助的朋友们

  • 感谢Aviv Ben Yosef 提供了第一个来自 Redis 外部的 PR。
  • 感谢Benjamin Winkler 对 README 的改进。
  • 感谢Dani Patko 实现了 .sortBy、.min 和 .max。
  • 感谢DidaS 在改进 Redis OM 的性能和代码质量方面的所有帮助。也感谢他的 linter。
  • 感谢Luc 实现了那位陌生人建议的更改。并感谢他的热情支持。
  • 感谢Simon Green 将测试套件的速度提高了几个数量级。
  • 感谢我的好朋友Nilanjan 敢于在生产环境中使用预览版软件,并提供了大量的反馈。*Fortuna audentes iuvat*(命运眷顾勇者)。

 我确定我可能遗漏了一些人,但请记住 GitHub 的提交历史永远不会忘记。