Return 到 lodash 链接中的父对象“_.chain()”

Return to parent object in lodash chaining "_.chain()"

我正在使用一个库 (lowdb),它在后台使用 lodash 在 json 文件中创建本地数据库。我想知道的是如何在修改子对象以修改另一个对象后到达 lodash 链接中的父对象,例如

const low = require('lowdb');
const FileSync = require('lowdb/adapters/FileSync');

const adapter = new FileSync('db.json');
const db = low(adapter);

/*
Eg. DB structure:
{
  "posts": [
    {
      "id": 1,
      "title": "post1"
    },
    {
      "id": 2,
      "title": "post2"
    },
    {
      "id": 3,
      "title": "post3"
    }
  ]
}
*/

db
  .get('posts')
  .find({ id: 2 })
  .assign({ title: 'edited title' }) 
  //after that I want to go back to posts to edit another one in the same chain
  .write();

我知道它可以在多个调用中完成,但我想知道是否可以在一个链中完成。

简答

如果您的目标是使代码尽可能美观,我建议您使用 lodash-id 及其 updateById 函数。我在我的长篇回答中介绍了所有可能的解决方案,但我个人会避免直接链接,而是做类似的事情:

const lodashId = require('lodash-id');
const low = require('lowdb');
const FileSync = require('lowdb/adapters/FileSync');

const adapter = new FileSync('db.json');
const db = low(adapter);
db._.mixin(lodashId);

const posts = db.get("posts");
posts.updateById( 1, { title: 'edited title 1' }).commit();
posts.updateById( 2, { title: 'edited title 2' }).commit();
posts.updateById( 3, { title: 'edited title 3' }).commit();
posts.write();

长答案

有几种方法可以解决这个问题,updateById 并不是目前唯一的方法。事实上,也可以通过使用 tap 函数在一个链中执行此操作。下面我介绍几种方案。

我可以在浏览器中快速试用这些功能吗?

当然可以!我实际上制作了一个 Codepen,您可以在其中直接在浏览器中尝试所有不同的可能方法,只需记得打开浏览器控制台查看测试结果!这是 link: https://codepen.io/jhack_jos/pen/XWNrpqX

如何调用函数?

所有这些函数都接收一个适配器作为输入。你可以这样称呼他们:

const result = testcaseXY(adapter);

1A) 点击并查找+分配

function testcase1A(adapter)
{
  const db = low(adapter);
  return db
    .get("posts")
    .tap( (posts) => _.chain(posts).find({ id: 1 }).assign({ title: 'edited title 1' }).commit())
    .tap( (posts) => _.chain(posts).find({ id: 2 }).assign({ title: 'edited title 2' }).commit())
    .tap( (posts) => _.chain(posts).find({ id: 3 }).assign({ title: 'edited title 3' }).commit())
    .write();
}

什么是 tap

  • 它是 lodash
  • 的效用函数
  • 它不直接改变数据库
  • 但是,它确实将对对象 hold 的引用传递给 interceptor 函数(在本例中我使用了箭头函数)
  • 可以更改对值的引用,从而影响数据库中的对象
  • 在数据库上调用 .write() 使更改确定。

2A) 点击并查找+设置

function testcase2A(adapter)
{
  const db = low(adapter);
  _.mixin(lodashId);
  return db
    .get("posts")
    .tap( (posts) => _.chain(posts).find({ id: 1 }).set("title", 'edited title 1').commit())
    .tap( (posts) => _.chain(posts).find({ id: 2 }).set("title", 'edited title 2').commit())
    .tap( (posts) => _.chain(posts).find({ id: 3 }).set("title", 'edited title 3').commit())
    .write();
}

什么是 set

  • 这是一种比 .assign 更简单的方法,但只有一个 属性.
  • 您可能期望 .set.assign
  • 更快

3A) 点击并更新 Id

function testcase3A(adapter)
{
  const db = low(adapter);
  _.mixin(lodashId);
  return db
    .get("posts")
    .tap( (posts) => _.chain(posts).updateById( 1, { title: 'edited title 1' }).commit())
    .tap( (posts) => _.chain(posts).updateById( 2, { title: 'edited title 2' }).commit())
    .tap( (posts) => _.chain(posts).updateById( 3, { title: 'edited title 3' }).commit())
    .write();
}

什么是 updateById

  • 这是一个由lodash-id library
  • 公开的函数
  • 你必须先将它作为mixin添加到lowdb
  • 要这样做,您首先需要使用 const lodashId = require('lodash-id')
  • 来要求它
  • 那么你需要调用db._.mixin(lodashId);
  • 这里我直接调用 _.mixin(lodashId),因为我直接在 tap 函数中使用 lodash,没有经过 lowdb

1B) 临时变量 & find+assign

function testcase1B(adapter)
{
  const db = low(adapter);
  const posts = db.get("posts");
  posts.find({ id: 1 }).assign({ title: 'edited title 1' }).commit();
  posts.find({ id: 2 }).assign({ title: 'edited title 2' }).commit();
  posts.find({ id: 3 }).assign({ title: 'edited title 3' }).commit();
  return posts.write();
}

如您所见,在这里使用临时变量可以使我们的代码更紧凑,更易于阅读、调试和重构。

2B) 临时变量 & find+set

function testcase2B(adapter)
{
  const db = low(adapter);
  const posts = db.get("posts");
  posts.find({ id: 1 }).set("title", 'edited title 1').commit();
  posts.find({ id: 2 }).set("title", 'edited title 2').commit();
  posts.find({ id: 3 }).set("title", 'edited title 3').commit();
  return posts.write();
}

3B) 临时变量 & updateById

function testcase3B(adapter)
{
  const db = low(adapter);
  db._.mixin(lodashId);
  const posts = db.get("posts");
  posts.updateById( 1, { title: 'edited title 1' }).commit();
  posts.updateById( 2, { title: 'edited title 2' }).commit();
  posts.updateById( 3, { title: 'edited title 3' }).commit();
  return posts.write();
}

感谢阅读!

如果您需要,我很乐意提供任何进一步的解释。 作为奖励,我要补充的是,可以将一些聪明的实用函数编写为 lowdb/lodash 混合,以使我们能够拥有更短的语法并仍然正确地链接。然而,这可能比您要找的更多。