如何将具有元素数组的每个对象的对象列表转换为具有子元素作为属性的对象数组
Posted
技术标签:
【中文标题】如何将具有元素数组的每个对象的对象列表转换为具有子元素作为属性的对象数组【英文标题】:How to convert a list of objects with each object having an array of elements, to an array of objects with the subelement as a property 【发布时间】:2020-11-07 03:01:13 【问题描述】:上下文
以Mongoose 和Pug 作为模板引擎的Node.js 项目示例 JSON 内容(使用 Mongoose 获取)
[
"name": "user1",
"blogs": [
"title": "blog1",
"created": "01-01-2020"
,
"title": "blog2",
"created": "01-01-2020"
]
,
"name": "user2",
"blogs": [
"title": "blog3",
"created": "01-01-2020"
,
"title": "blog4",
"created": "01-01-2020"
]
]
问题
我正在尝试显示所有博客文章的列表,按文章的创建日期排序,并显示创建它的用户。
在 Pug 中注入上述对象并执行 foreach 将按用户对所有表演进行分组,并且无法对所有表演的创建日期进行排序(在此对象形式中)。
我的解决方案将是以下对象:
示例 JSON,将每个博客条目映射到一个用户
[
"name": "user1",
"blog":
"title": "blog1",
"created": "01-01-2020"
,
"name": "user1",
"blog":
"title": "blog2",
"created": "01-01-2020"
,
"name": "user2",
"blog":
"title": "blog3",
"created": "01-01-2020"
,
"name": "user2",
"blog":
"title": "blog4",
"created": "01-01-2020"
]
这种对象形式可以使每个博客条目仍然显示用户的数据并按演出的创建日期排序。
我正在尝试实现后者,但我还没有找到一种没有 foreaching 或映射的干净方法。
注意
这个问题可以很容易地通过定义关系和解析键来解决,但我明确地试图用NoSQL来解决这个问题。 因此,博客实体中没有用户的引用。
你会如何解决这个问题?这个特定操作的特征名称是什么?
【问题讨论】:
【参考方案1】:您可以使用聚合从 MongoDB 中以所需格式获取数据,而不是先以您不想要的格式从数据库中获取数据,然后将其转换为您想要的格式:
db.collection.aggregate([
$unwind: "$blogs" ,
$project:
"_id": 0,
name: 1,
blogs: 1,
date:
$dateFromString:
dateString: "$blogs.created"
,
$sort: date: -1 ,
$project: date: 0
])
上述查询中使用的聚合管道阶段说明:
$unwind
- 解构blogs
数组以输出一个单独的文档,其中包含blogs
数组中的每个对象
$project
- 隐藏_id
字段,显示name
和blogs
字段并创建一个名为date
的新字段并将其值设置为等于转换为日期的字段created
。 (created
字段的值被转换为日期,以便根据日期而不是日期字符串对文档进行正确排序。)
$sort
- 根据date
字段按降序对文档进行排序(-1 表示降序,1 表示升序),即从最近的日期到较旧的日期。
$project
- 从输出文档中隐藏date
字段
有关上述聚合管道阶段的详细信息,请参阅:
$unwind $sort $project演示:
This demo 显示了上面提到的查询。
【讨论】:
展开是我一直在寻找的关键词!谢谢。【参考方案2】:试试Array.prototype.reduce
。像这样 -
const data = [
"name": "user1",
"blogs": [
"title": "blog1",
"created": "01-01-2020"
,
"title": "blog2",
"created": "01-01-2020"
]
,
"name": "user2",
"blogs": [
"title": "blog3",
"created": "01-01-2020"
,
"title": "blog4",
"created": "01-01-2020"
]
];
const result = data.reduce((acc, curr) =>
const name, blogs = curr;
const blogArr = blogs.map((blog) =>
return
name,
blog
;
);
Array.prototype.push.apply(acc, blogArr);
return acc;
, []);
console.log(result);
【讨论】:
【参考方案3】:我会使用 MongoDB 提供的命名聚合功能。 聚合可以让您在获取数据之前按照自己的意愿格式化数据。
聚合以管道格式工作。你给它一个命令列表,这些命令将按照你发送它的顺序执行。
在这种情况下,聚合管道如下所示:
[
$unwind:
path: '$blogs'
,
$project:
_id: 0,
name: 1,
blog: '$blogs'
,
$sort:
"blogs.created": -1
]
此管道中使用的命令:
$unwind - 将项目数组解构为多个文档,这些文档都包含原始文档的原始字段,但 unwound 字段现在具有数组中所有解构对象的值。
$project - 它让您可以根据需要格式化数据、删除字段、添加字段和重命名字段。
$sort - 顾名思义,它可以让您对文档进行排序,指定要排序的字段和顺序(升序或降序)。
有关聚合的更多信息,请访问 MongoDB 的网站:
Aggregation $unwind $project $sort【讨论】:
太棒了,我没有考虑使用聚合,因为我认为它会使操作过于复杂,但这实际上非常简洁!以上是关于如何将具有元素数组的每个对象的对象列表转换为具有子元素作为属性的对象数组的主要内容,如果未能解决你的问题,请参考以下文章
将每个具有一个对象的 JSON 对象数组转换为 JSON 对象数组 [关闭]
JavaScript:将具有父键的对象数组转换为父/子树(包括没有父的对象)