【问题标题】:Map multiple objects to single object in stream将多个对象映射到流中的单个对象
【发布时间】:2016-10-02 09:12:56
【问题描述】:

我有一些非常大 (> 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/...'
    }
}

我是用这样的小数据集实现的,首先处理“原始”大小:

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 重新映射,那就太好了。

当然,我不可能是第一个遇到这种问题的人。过去使用了哪些解决方案?我该如何处理?

【问题讨论】:

  • 输入数组中不同维度的对象不是总是相邻吗?
  • 您确定要通过它们的时间戳而不是它们的 id 来匹配它们吗?
  • 我的例子可能具有误导性。不,不幸的是,这些对象根本不相邻,并且可能位于文件中的任何位置。是的,按时间戳匹配是我想要的。这是对具有特定 ID 的所有记录进行操作,因此在这里并不太重要。
  • 每个属性是否都在自己的行中,如您的问题中所述?例如,id 在一行,timestamp 在下一行,等等
  • 不,每个对象一行一行。

标签: javascript node.js node-streams


【解决方案1】:

设置一些可以存储 JSON 文档的数据库实例。 MongoDB 或 PostgreSQL(最近他们引入了 jsonb 数据类型来存储 json 文档)。遍历旧的 JSON 文档并将它们组合成新的结构,使用 DB 作为存储 - 这样您就可以克服内存问题。

我很确定,如果不 a) 降低进程的速度(极大地)或 b) 从头开始​​创建穷人的数据库(这似乎是一件坏事 :),就无法实现您的目标)

【讨论】:

    【解决方案2】:

    我认为诀窍是即时更新数据库。如果 JSON 文件对于内存来说太大了,那么我预计生成的对象集(在您的示例中为 out)对于内存来说也太大了。

    在 cmets 中,您声明 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 对我来说失败了。

    【讨论】:

      猜你喜欢
      • 2018-08-24
      • 2019-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多