简体   繁体   English

使用 lodash 创建多级查找表

[英]Create multi-level lookup table with lodash

Lets pretend an api is returning the structure in apiResult , and I want to create a two-level index for looking up what comments a given author have made on a given article.让我们假设一个 api 正在返回apiResult的结构,我想创建一个两级索引来查找给定作者对给定文章发表的评论。

The lookup table for the authors, articles and comments it self is easy enough, but I struggle with the CommentsByArticleAndAuthor -lookup.作者、文章和评论的查找表本身很容易,但我很难使用CommentsByArticleAndAuthor -lookup。

In the mapped structure, I'm showing how I'm making the lookup index for the three 'easy' parts, and also how I want the CommentsByArticleAndAuthor to look.mapped结构中,我展示了如何为三个“简单”部分创建查找索引,以及我希望CommentsByArticleAndAuthor的外观。

How can I go forward generating this index?我怎样才能继续生成这个索引?

 var apiResult = { Authors: [ { Id: "author-id-1", Name: "Author One" }, { Id: "author-id-2", Name: "Author Two" } ], Articles: [ { Id: "article-id-1", Title: "This Great Article" } ], Comments: [ { Id: "comment-id-1", AuthorId: "author-id-1", ArticleId: "article-id-1", Comment: "that great, hu?" }, { Id: "comment-id-2", AuthorId: "author-id-2", ArticleId: "article-id-1", Comment: "yes, that great" } ] } var mapped = { Authors: _.keyBy(apiResult.Authors, 'Id'), Articles: _.keyBy(apiResult.Articles, 'Id'), Comments: _.keyBy(apiResult.Comments, 'Id'), CommentsByArticleAndAuthor: { "article-id-1": { "author-id-1": [ "comment-id-1" ], "author-id-2": [ "comment-id-2" ] } } } console.log(JSON.stringify(mapped, null, 2));
 <script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>

You could iterate the comments and build a hierarchical object strcture.您可以迭代注释并构建分层对象结构。

 var apiResult = { Authors: [{ Id: "author-id-1", Name: "Author One" }, { Id: "author-id-2", Name: "Author Two" }], Articles: [{ Id: "article-id-1", Title: "This Great Article" }], Comments: [{ Id: "comment-id-1", AuthorId: "author-id-1", ArticleId: "article-id-1", Comment: "that great, hu?" }, { Id: "comment-id-2", AuthorId: "author-id-2", ArticleId: "article-id-1", Comment: "yes, that great" }] }, mapped = { CommentsByArticleAndAuthor: {} }; apiResult.Comments.forEach(function (o) { var ref = mapped.CommentsByArticleAndAuthor; ref[o.ArticleId] = ref[o.ArticleId] || {}; ref[o.ArticleId][o.AuthorId] = ref[o.ArticleId][o.AuthorId] || []; ref[o.ArticleId][o.AuthorId].push(o.Id); }); console.log(mapped);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

For a more dynamic approach, you could use an array for the hierarchy and an object for the default values.对于更动态的方法,您可以使用一个数组作为层次结构,并使用一个对象作为默认值。

 var apiResult = { Authors: [{ Id: "author-id-1", Name: "Author One" }, { Id: "author-id-2", Name: "Author Two" }], Articles: [{ Id: "article-id-1", Title: "This Great Article" }], Comments: [{ Id: "comment-id-1", AuthorId: "author-id-1", ArticleId: "article-id-1", Comment: "that great, hu?" }, { Id: "comment-id-2", AuthorId: "author-id-2", ArticleId: "article-id-1", Comment: "yes, that great" }] }, mapped = { CommentsByArticleAndAuthor: {} }; apiResult.Comments.forEach(function (o) { ['ArticleId', 'AuthorId'].reduce(function (r, k) { return r[o[k]] = r[o[k]] || { AuthorId: [] }[k] || {}; }, mapped.CommentsByArticleAndAuthor).push(o.Id); }); console.log(mapped);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

You can reduce the apiResult.Comments into the desired result:您可以将apiResult.Comments减少为所需的结果:

CommentsByArticleAndAuthor: apiResult.Comments.reduce((result, comment) => Object.assign(result, {
  [comment.ArticleId]: Object.assign(result[comment.ArticleId] || {}, {
    [comment.AuthorId]: result[comment.ArticleId] && result[comment.ArticleId][comment.AuthorId]
      ? result[comment.ArticleId][comment.AuthorId].push(comment.Id)
      : [comment.Id]
  })
}), {})

Your example:你的例子:

 var apiResult = { Authors: [ { Id: "author-id-1", Name: "Author One" }, { Id: "author-id-2", Name: "Author Two" } ], Articles: [ { Id: "article-id-1", Title: "This Great Article" } ], Comments: [ { Id: "comment-id-1", AuthorId: "author-id-1", ArticleId: "article-id-1", Comment: "that great, hu?" }, { Id: "comment-id-2", AuthorId: "author-id-2", ArticleId: "article-id-1", Comment: "yes, that great" } ] } var mapped = { CommentsByArticleAndAuthor: { "article-id-1": { "author-id-1": [ "comment-id-1" ], "author-id-2": [ "comment-id-2" ] } }, CommentsByArticleAndAuthor: apiResult.Comments.reduce((result, comment) => Object.assign(result, { [comment.ArticleId]: Object.assign(result[comment.ArticleId] || {}, { [comment.AuthorId]: result[comment.ArticleId] && result[comment.ArticleId][comment.AuthorId] ? result[comment.ArticleId][comment.AuthorId].push(comment.Id) : [comment.Id] }) }), {}) } console.log(mapped);
 <script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>

Thanks to Ninas great answer I came up with this generic solution:感谢Ninas 的出色回答,我想出了这个通用解决方案:

 const apiResult = { Authors: [{ Id: "author-id-1", Name: "Author One" }, { Id: "author-id-2", Name: "Author Two" }], Articles: [{ Id: "article-id-1", Title: "This Great Article" }], Comments: [{ Id: "comment-id-1", AuthorId: "author-id-1", ArticleId: "article-id-1", Comment: "that great, hu?" }, { Id: "comment-id-2", AuthorId: "author-id-2", ArticleId: "article-id-1", Comment: "yes, that great" }] }; const mapped = {}; const indexBy = function(collection, keys, map = (item) => item) { let result = {}; collection.forEach((item) => { keys.reduce((r, k, idx) => { let value = _.get(item, k); if (idx === keys.length - 1) return r[value] = [...r[value] || [], map(item)]; return r[value] = r[value] || {} }, result); }); return result; } mapped.CommentsByArticlesAndAuthor = indexBy(apiResult.Comments, ['ArticleId', 'AuthorId'], (item) => item.Id); mapped.CommentsByAuthorAndArticle = indexBy(apiResult.Comments, ['AuthorId', 'ArticleId'], (item) => item.Id); console.log(mapped);
 .as-console-wrapper { max-height: 100% !important; top: 0; }
 <script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>

It let me index on as many levels that I want, and it let me transform the item indexed, defaulting to just store the full item.它让我可以在我想要的多个级别上建立索引,并让我转换索引的项目,默认只存储完整的项目。 It also utilize get from lodash to support nested key values, eg Author.Id instead of AuthorId .它还利用get从lodash支持嵌套的关键值,例如Author.Id而不是AuthorId

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM