我需要对我收到的数据进行一些额外的过滤,这样我才能获得符合特定条件的数据。我试图找到一个运算符组合,我可以通过函数式编程方法来实现这一点。我想也许filter
和reduce
的组合可能有效吗?我可以简单地将它们的组合链接在一起以获得我正在寻找的结果吗?
我的数据结构如下:
"data": [
{
"_id": "53545",
"services": [
{
"service": "service1",
"history": [
{
"_id": "6546",
"status": "stage1",
"completed": true
},
{
**"_id": "6547",
"status": "stage2",
"completed": false**
}
],
{
"service": "service2",
"history": [
{
"_id": "6743",
"status": "stage3",
"completed": false
},
{
"_id": "3742",
"status": "stage2",
"completed": true
}
]
},
{
"service": "service3",
"history": [
{
"_id": "6448",
"status": "stage4",
"completed": false
},
{
"_id": "4443",
"status": "stage1",
"completed": true
}
]
}
]
要明确,此处data
,services
和history
是所有数组。在上述数据的情况下,只有一个对象在"历史"应该通过测试,因为只有一个对象,其中"状态:stage2"并且"完成:false"。但这意味着,在"数据"数组,这个特殊的对象,一个带有" _id":" 53545"应该通过,因为测试返回true。最终,我想要从"数据"中的对象内返回一个数组。数组,像这样的匹配。
非常具体地说,就我而言,总有3项服务。在这3个中的每一个中,可能存在1个或多达30个或更多个历史对象。我需要浏览所有3"服务",并找到状态为" stage2"的历史对象。并且"完成:false"。因此,如果三个服务中的任何一个具有" status:stage2"的历史对象,则应返回true。和"完成:false"。
我绊倒了迭代数组中的数组。
我可以这样直接得到它:
let stage2Data = data.filter(data => data.services[0].history[1].status === 'stage2' && data.services[0].history[1].completed === false);
但是,我显然不知道这些不同数组中的项目编号将包含我正在寻找的值。那么解决这个问题的最佳方法是什么?我想一系列for-of循环也可以起作用,但是我想使用一种更实用的方法,并且正在考虑将" filter"和"减少",或者" map"可以在这里工作。我怎样才能返回"数据中的对象"数组其中" "status": "stage2"
和"completed": false
对于"历史"中的至少一个对象为真。阵列
答案 0 :(得分:2)
根据您希望的结果数据,这里有一个开始。您可以使用几个嵌套过滤器来强制执行此操作:
result = data.filter((datum) => {
return datum.services.filter((service) => {
return service.history.filter((h) => {
return h.completed && h.status === "stage2"
}).length > 0;
}).length > 0;
});
tl; dr - 按照任何具有至少一个在第2阶段完成的历史记录的服务的数据过滤主列表。
工作小提琴:http://jsbin.com/jozujezidu/edit?js,console,output
如果希望结果数组只包含通过过滤器的历史记录,则必须修改代码。另外,这是一个On ^ 3,所以如果这个数据可能很大,你应该修改这个方法。但这应该让你前进。
不要担心激进的功能。如果你能找到一个人们可以理解和维护的工作解决方案,那么这是一个良好的开端。
答案 1 :(得分:2)
我们一直在评论中来回试图在您的问题中获得有效的数据结构。让我举一个简单的例子,告诉你如何让每个人都更轻松。
首先,使用编辑框顶部的代码段按钮创建代码段。这个图标看起来像是一个典型的“折角”文档图标,里面有<>
。
这将打开一个包含HTML / CSS / JavaScript代码的弹出框。忽略HTML和CSS框并将数据对象粘贴到JavaScript框中。
因为它不是“原样”的JavaScript,所以将它包装在赋值语句中以获取可以使用的JavaScript变量。
然后在末尾添加console.log
语句以显示数据。使用运行按钮确保代码实际解析并运行并正确显示数据。一旦你这样做,人们就会更容易 来帮助你。
这是一个简化的例子:
const input = {
"data": [
{
"one": "two"
},
{
"three": "four"
}
]
};
console.log( JSON.stringify( input, null, 4 ) );
点击上方的运行代码段按钮,查看此示例运行。请注意它是如何打印出我上面使用的相同数据结构。
如果您在问题中执行相同操作,则会强制您清理数据以使其实际有效。然后你给人们一些他们可以使用的东西。
另一个注意事项:不要试图以“功能”的方式做这件事。通过使用let output = [];
创建一个空数组,然后在每个嵌套数组(或.forEach()
循环上使用for...of
,如果您定位到最新的浏览器,您很可能会获得更易理解的代码),并在每个匹配元素上使用output.push()
。
为了说明,假设我正确理解了您的数据结构(假设您将其包含在input
变量中,如我的简化示例中所示),它可能看起来像这样:
let output = [];
input.data.forEach( function( dataItem ) {
dataItem.services.forEach( function( service ) {
service.history.forEach( function( historyItem ) {
if( ! historyItem.completed && historyItem.status == "stage2" ) {
output.push( historyItem );
}
});
});
});
或使用for...of
循环:
let output = [];
for( let dataItem of input.data ) {
for( let service of dataItem.services ) {
for( let historyItem of service.history ) {
if( ! historyItem.completed && historyItem.status == "stage2" ) {
output.push( historyItem );
}
}
}
}
当然,这些都是未经测试的。无论哪种方式,它都不是很花哨,但似乎很容易理解。
答案 2 :(得分:0)
过滤操作将基于与您的值匹配的谓词。
如果您想要服务对象列表,请尝试以下方法:
let result = data[0].services.filter((item) => item.history.some((h) => h.status=='stage2' && h.completed==false));