2015-01-30 4 views
2

Я работал с mongodb, но совершенно новым для mongoose ORM. Я пытался получить данные из коллекции, а вывод explain() показывал 50 мс. общее время, затрачиваемое на получение данных через мангуст, составляло 9 секунд. Вот запрос:конвертировать поток мангуста в массив

Node.find({'dataset': datasetRef}, function (err, nodes){ 
    // handle error and data here 
}); 

Затем я применил индекс в поле, на которое я запрашивал. Теперь результат explain() показал 4 мс. Но общее время для извлечения данных через мангуста не изменилось. Тогда я искал немного, и обнаружил, что использование мяса() может помочь принести производительность запросов на чтении в мангусте довольно близко к родному MongoDB

Так что я изменил мой запрос:

Node.find({'dataset': datasetRef}) 
.lean() 
.stream({transform: JSON.stringify}) 
.pipe(res) 

Это решило проблему с производительностью полностью. Но конечный результат представляет собой поток JSON документы, как это:

{var11: val11, var12: val12}{var21: val21, var22: val22} ... 

Как разобрать это, чтобы сформировать массив документации? Или я не должен использовать поток вообще? По-моему, нет смысла использовать поток, если я планирую сформировать массив на бэкэнд, так как мне придется ждать, пока все документы будут считаны в памяти. Но я также думаю, что разбор и создание всего массива на лицевой стороне может оказаться дорогостоящим.

Как добиться максимальной производительности в этом случае, не забивая сеть?

UPDATE

Я пытаюсь решить эту проблему с помощью сквозного потока. Тем не менее, я не могу вставлять запятые между объектами JSON. Смотрите код ниже:

res.write("["); 

var through = require('through'); 
var tr = through(
    function write(data){ 
    this.queue(data.replace(/\}\{/g,"},{")); 
    } 
); 

var dbStream = db.node.find({'dataset': dataSetRef}) 
.lean() 
.stream({'transform': JSON.stringify}); 

dbStream.on("end", function(){ 
    res.write("]"); 
}); 

dbStream 
.pipe(tr) 
.pipe(res); 

С этим я могу получить «[» в начале и «]» в конце. Тем не менее, все еще не удается получить patten "} {" replace with "}, {". Не уверен, что я делаю неправильно

UPDATE 2

Теперь понял, почему заменить не работает. Похоже, что, поскольку я определил функцию преобразования как JSON.stringify, он читает один объект JSON за раз и, следовательно, никогда не сталкивается с шаблоном }{, так как он никогда не выбирает несколько элементов JSON за раз.

Теперь я изменил свой код и написал пользовательскую функцию преобразования, которая делает JSON.stringify, а затем добавляет запятую в конце. Единственная проблема, с которой я столкнулся, заключается в том, что я не знаю, когда это последний объект JSON в потоке. Потому что я не хочу добавлять запятую в этом случае. В настоящий момент я добавляю пустой объект JSON после того, как встречается конец. Но почему-то это не похоже на убедительную идею. Вот код:

res.write("["); 
function transform(data){ 
    return JSON.stringify(data) + ","; 
} 

var dbStream = db.node.find({'dataset': dataSetRef}) 
.lean() 
.stream({'transform': transform}); 

dbStream.on("end", function(){ 
    res.write("{}]"); 
}); 

dbStream 
.pipe(res); 
+0

вы пробовали пропусканием постное вариант в первом запросе? Node.find ({'dataset': datasetRef}). Lean(). Exec (function (err, nodes) {...}); – joao

+0

Да. Дело в том, что документы ранее хранились как один массив в документе и сохранялись в gridfs. Таким образом, раньше, когда запрос был запрошен, ответ начал поток в течение нескольких миллисекунд. Теперь, если я перехожу от этой модели к этой нормированной модели, исключая gridfs, мне нужно использовать поток, иначе ответ откладывается с обратной стороны. –

+0

можно каким-то образом использовать сквозной поток для замены шаблонов типа '} {' with '}, {'? Я пытаюсь, но не в состоянии это сделать –

ответ

3

Единственная проблема, я столкнулся здесь в том, что я не знаю, когда это последний объект JSON в потоке.

Но вы знаете, кто из них первый. Зная, что вместо добавления запятой вы можете добавить его к каждому объекту, кроме первого.Для того, чтобы сделать это, настроить функцию преобразования внутри закрытия:

function transformFn(){ 

    var first = true; 

    return function(data) { 

     if (first) { 

      first = false; 
      return JSON.stringify(data); 
     } 
     return "," + JSON.stringify(data); 
    } 
} 

Теперь вы можете просто позвонить эту функцию и установить его в качестве фактического преобразования.

var transform = transformFn(); 
res.write("["); 
var dbStream = db.node.find({'dataset': dataSetRef}) 
.lean() 
.stream({'transform': transform}); 

dbStream.on("end", function(){ 
    res.write("]"); 
}); 

dbStream 
.pipe(res); 
+0

понравилось решение! –

1

Я люблю @ решения cdbajorin, поэтому я создал более читаемую версию этого (ES6):

Products 
    .find({}) 
    .lean() 
    .stream({ 
     transform:() => { 
      let index = 0; 
      return (data) => { 
       return (!(index++) ? '[' : ',') + JSON.stringify(data); 
      }; 
     }() // invoke 
    }) 
    .on('end',() => { 
     res.write(']'); 
    }) 
    .pipe(res); 
3

@cbajorin и @rckd оба дали правильные ответы.

Однако повторение этого кода все время кажется больным.

Следовательно, мое решение использует дополнительный поток Transform для достижения того же.

import { Transform } from 'stream' 

class ArrayTransform extends Transform { 
    constructor(options) { 
     super(options) 
     this._index = 0 
    } 

    _transform(data, encoding, done) { 
     if (!(this._index++)) { 
      // first element, add opening bracket 
      this.push('[') 
     } else { 
      // following element, prepend comma 
      this.push(',') 
     } 
     this.push(data) 
     done() 
    } 

    _flush(done) { 
     if (!(this._index++)) { 
      // empty 
      this.push('[]') 
     } else { 
      // append closing bracket 
      this.push(']') 
     } 
     done() 
    } 
} 

Который в свою очередь, может быть использован как:

const toArray = new ArrayTransform(); 
Model.find(query).lean().stream({transform: JSON.stringify }) 
    .pipe(toArray) 
    .pipe(res) 

EDIT: добавлена ​​проверка на пустой

+0

люблю его. thx для обмена – rckd

0
var mongoose = require('mongoose'); 
    mongoose.connect('mongodb://localhost/shoppingdb'); 
    var Sports = mongoose.model('sports', {}); 

    var result = []; 
    var prefix_out = "your info"; 

     Sports.find({"goods_category": "parts"}). 
     cursor(). 
     on("data", function(doc){ 
     //stream ---> string 
      var str = JSON.stringify(doc) 
     //sring ---> JSON 
      var json = JSON.parse(str); 
     //handle Your Property 
      json.handleYourProperty = prefix_out + json.imageURL;    
      result.push(result); 
     }). 
     on('error', function(err){ 
      console.log(err); 
     }). 
     on('close', function(){ 
      console.log(result); 
     }); 
Смежные вопросы