Существует два файла, упорядоченные по id, parent_data.json и child_data.json. Дети являются подмножеством родителей.
Я пытаюсь сопоставить parent.id с child.id. Я пытаюсь сделать один проход на файл .json. Вместо того, чтобы делать что-то наподобие вложенного forEach / map, которое проходит через каждого потомка.
Предположим, что оба файла .json содержат несколько гигов / миллионов строк, перечитывание children.json займет много времени с несколькими проходами, и загрузка всего в память также не может быть и речи.
Каждый файл может иметь формат JSON или NDJSON . Текущий пример - NDJSON.
parent_data.json:
{"id":1, "name": "parent_1"}
{"id":2, "name": "parent_2"}
{"id":3, "name": "parent_3"}
{"id":4, "name": "parent_4"}
{"id":5, "name": "parent_5"}
{"id":6, "name": "parent_6"}
{"id":7, "name": "parent_7"}
child_data.json:
{"id":4, "name":"belongs_to_parent_4", "guid": "${unique_id}"}
{"id":4, "name":"belongs_to_parent_4", "guid": "${unique_id}"}
{"id":5, "name":"belongs_to_parent_5", "guid": "${unique_id}"}
{"id":7, "name":"belongs_to_parent_7", "guid": "${unique_id}"}
{"id":7, "name":"belongs_to_parent_7", "guid": "${unique_id}"}
Ожидаемый результат:
[
{
"id": 4,
"name": "parent_4",
"children": [
{
"id": 4,
"name": "belongs_to_parent_4",
"guid": "${unique_id}"
},
{
"id": 4,
"name": "belongs_to_parent_4",
"guid": "${unique_id}"
}
]
},
{
"id": 5,
"name": "parent_5",
"children": [
{
"id": 5,
"name": "belongs_to_parent_5",
"guid": "${unique_id}"
}
]
},
{
"id": 7,
"name": "parent_7",
"children": [
{
"id": 7,
"name": "belongs_to_parent_7",
"guid": "${unique_id}"
}
]
}
]
Я не могу найти достойный способ перебрать любой из потоков, не пропустив несколько дочерних элементов в конечном результате.
Этот код пропускает двух первых потомков каждого из родителей:
const fs = require('fs');
const es = require('event-stream');
const main = () => {
let currentParent = null;
let currentChild = null;
let prevChild = null;
let parentLines = 0;
let childLines = 0;
let tmpChildren = [];
const parentStream = fs
.createReadStream('parent_data.json') // Parent Stream
.pipe(es.split('\n')) // Delimit by \n
.pipe(
es.mapSync(line => { // Current line, without the delimiter \n
parentStream.pause(); // Pause stream until done processing this line
++parentLines; // Debug
currentParent = JSON.parse(line); // Now it's valid JSON object
console.log('currentParent', currentParent.id); // Debug
}),
)
.on('error', e => {
console.error(e);
})
.on('close', () => {
console.log('close reading parent stream');
})
.on('end', () => {
console.log('end reading parent stream');
});
const childStream = fs
.createReadStream('child_data.json') // Child Stream
.pipe(es.split('\n')) // Split by delimiter
.pipe(
es.mapSync(line => { // Current child line, without delimiter
++childLines; // Debug
childStream.pause(); // Pause child stream
currentChild = JSON.parse(line); // Valid JSON child now
if (prevChild && (currentParent.id === prevChild.id)) { // Check prevChild and currentParent
tmpChildren.push(prevChild);
prevChild = null;
}
if (currentChild && (currentParent.id == currentChild.id)) { // Check currentChild and currentParent
console.log('child', currentChild.id);
tmpChildren.push(currentChild);
// childStream.resume(); // Having this here will cause the stream to stop processing entirely
} else {
// We're here because currentParent does not match currentChild, move to next parent
prevChild = currentChild;
if (tmpChildren.length > 0) {
currentParent['children'] = tmpChildren;
tmpChildren = [];
}
parentStream.resume();
}
console.log('currentChild', currentChild.id);
childStream.resume(); // Having this here will cause the stream to skip children on new parent
}),
)
.on('error', e => {
console.error(e);
})
.on('close', () => {
console.log('close reading child stream');
})
.on('end', () => {
console.log('end reading child stream');
});
};
main();
TLDR: Соответствует parent.id для child.id, если нет совпадений, сохраните child. Перейдите к следующему родителю, проверьте для prevChild.id и / или child.id на parent.id. Если совпадение добавит prevChild / child к parent [children], выполните итерацию child. Если совпадений нет, переходите к следующему родителю ... и т.д.
Может быть, графика поможет