2016-06-02 1 views
0

새로운 형식으로 매핑하고 새 DB에 업로드해야하는 매우 큰 (> 500MB) JSON 파일이 있습니다.여러 객체를 스트림의 단일 객체에 매핑

이전 형식 :

{ 
    id: '001', 
    timestamp: 2016-06-02T14:10:53Z, 
    contentLength: 123456, 
    filepath: 'original/...', 
    size: 'original' 
}, 
{ 
    id: '001', 
    timestamp: 2016-06-02T14:10:53Z, 
    contentLength: 24565, 
    filepath: 'medium/...', 
    size: 'medium' 
}, 
{ 
    id: '001', 
    timestamp: 2016-06-02T14:10:53Z, 
    contentLength: 5464, 
    filepath: 'small/...', 
    size: 'small' 
} 

새로운 형식 :

{ 
    Id: '001', 
    Timestamp: 2016-06-02T14:10:53Z, 
    OriginalSize: { 
     ContentLength: 123456, 
     FilePath: 'original/...' 
    }, 
    MediumSize: { 
     ContentLength: 24565, 
     FilePath: 'medium/...' 
    }, 
    SmallSize: { 
     ContentLength: 5464, 
     FilePath: 'small/...' 
    } 
} 

I는, 이와 같은 작은 데이터 셋이 달성 먼저 '원본'크기를 처리 하였다

let out = data.filter(o => o.size === 'original).map(o => { 
    return { 
     Id: o.id, 
     Timestamp: o.timestamp, 
     OriginalSize: { 
      ContentLength: o.contentLength, 
      FilePath: o.filepath 
     } 
    }; 
}); 
data.filter(o => o.size !== 'original').forEach(o => { 
    let orig = out.find(function (og) { 
     return og.Timestamp === o.timestamp; 
    }); 
    orig[o.size + 'Size'] = { 
     ContentLength: o.contentLength, 
     FilePath: o.filepath 
    }; 
) 
// out now contains the correctly-formatted objects 

이 문제는 수백 메가 바이트의 JSON을 메모리에로드 할 수없는 매우 큰 데이터 세트에서 발생합니다 한꺼번에. 이것은 스트림을 사용하는 좋은 시간 인 것 같습니다. 물론 파일을 청크로 읽는다면 .find()를 작은 배열로 실행하면 '원본'크기를 찾을 수 없습니다. 전체 파일을 스캔하여 원본을 찾은 다음 다시 스캔하여 내가 찾은 것에 다른 크기를 추가하면 어쨌든 전체 데이터 세트로 끝납니다.

나는 JSONStream을 알고 있는데, 내 물건을 간단한 1-1 매핑으로하면 멋질 것입니다.

분명히 나는 ​​이런 종류의 문제에 부딪 칠 수있는 첫 번째 사람이 될 수 없습니다. 과거에 어떤 솔루션이 사용 되었습니까? 어떻게 접근 할 수 있습니까?

+0

서로 다른 차원의 객체가 항상 입력 배열에서 서로 인접합니까? – Bergi

+0

ID가 아닌 타임 스탬프로 일치 시키시겠습니까? – Bergi

+0

예가 잘못되었을 수 있습니다. 불행히도 객체는 전혀 인접하지 않으며 파일의 어느 곳에 나있을 수 있습니다. 그리고 네, 타임 스탬프에 의한 매칭은 제가 원하는 것입니다. 이것은 특정 ID를 가진 모든 레코드에서 작동하므로 여기서 너무 중요하지 않습니다. –

답변

0

트릭은 데이터베이스를 즉시 업데이트하는 것이라고 생각합니다. JSON 파일이 너무 커서 메모리가 크다면 그 결과 객체 세트 (예 : out)가 너무 커서 메모리를 사용할 수 없을 것으로 예상됩니다.

주석에는 JSON 파일에 한 줄에 하나의 객체가 있다고 설명되어 있습니다. 따라서 node.js를 사용하여 fs.createReadStreamreadline을 텍스트 파일의 각 줄을 가져옵니다. 다음은 json 객체에 라인 (문자열)을 처리하고 마지막으로 데이터베이스를 업데이트합니다.

parse.js

var readline = require('readline'); 
var fs = require('fs'); 

var jsonfile = 'text.json'; 

var linereader = readline.createInterface({ 
    input: fs.createReadStream(jsonfile) 
}); 

linereader.on('line', function (line) { 
    obj = parseJSON(line); // convert line (string) to JSON object 

    // check DB for existing id/timestamp 
    if (existsInDB({id:obj.id, timestamp:obj.timestamp})) { 
    updateInDB(obj); // already exists, so UPDATE 
    } 
    else { insertInDB(obj); } // does not exist, so INSERT 
}); 


// DUMMY functions below, implement according to your needs 

function parseJSON (str) { 
    str = str.replace(/,\s*$/, ""); // lose trailing comma 
    return eval('(' + str + ')'); // insecure! so no unknown sources 
} 
function existsInDB (obj) { return true; } 
function updateInDB (obj) { console.log(obj); } 
function insertInDB (obj) { console.log(obj); } 

text.json

{ id: '001', timestamp: '2016-06-02T14:10:53Z', contentLength: 123456, filepath: 'original/...', size: 'original' }, 
{ id: '001', timestamp: '2016-06-02T14:10:53Z', contentLength: 24565, filepath: 'medium/...', size: 'medium' }, 
{ id: '001', timestamp: '2016-06-02T14:10:53Z', contentLength: 5464, filepath: 'small/...', size: 'small' } 

참고 : 나는 구문 오류를 방지하기 위해 타임 스탬프 값을 인용 할 필요가 있었다. 귀하의 질문 및 예제 스크립트에서 나는이 문제가 없거나 이미이 문제가 해결 되었으면합니다. 아마도 다른 방법 일 것입니다.

또한 parseJSON의 구현은 JSON을 구문 분석하는 것과 다를 수 있습니다. 평범한 오래된 JSON.parse은 속성이 인용되지 않아 나를 위해 실패했습니다.

+0

고마워,이게 내가 올바른 방향으로 갈 수있게 해줬 어. –

0

JSON 문서를 저장할 수있는 DB 인스턴스를 설정하십시오. MongoDB 또는 PostgreSQL (최근에 jsonb 문서를 저장하기 위해 jsonb 데이터 유형을 도입했습니다). 이전 JSON 문서를 반복하고 DB를 저장소로 사용하여 새로운 구조에 결합하면 메모리 문제를 극복 할 수 있습니다.

나는 프로세스의 속도를 저해하거나 (극적으로) 또는 가난한 사람의 DB를 처음부터 만들지 않고서도 목표를 성취 할 방법이 없다고 확신한다.))