Импорт CSV в neo4j с использованием node.js

1

Я пытаюсь импортировать файл csv в neo4j с помощью neo4j Мне нужно вставить данные в несколько collection/table, поэтому мне нужно вставить данные, используя script.js. Но моя проблема заключается в том, что я не могу предотвратить дублирование данных при вставке данных csv.

Примеры данных CSV:

name
-------------
Afghanistan
Afghanistan
Aland
Albania
Albania
Bangladesh
Bangladesh

index.js

cp = require('child_process');
child = cp.fork(__dirname + "/background-import-csv-file.js");
child.on('message', function(msg) {
    console.log("background-insert-process said : ", msg);
});
file = path.resolve(__dirname, './file/simplemaps.csv');
child.send(file);

В background-import-csv-file.js меня есть код записи двумя разными способами.

Первое основанное на обещании (background-import-csv-file.js):

cp = require('child_process');
csv = require('fast-csv');
Q = require('q');
DB = require("./common/driver");
Country = require('./collection/country');
process.on("message", (file) => {
  stream = fs.createReadStream(file);
  csv
    .fromStream(stream, { headers: true })
    .on("data", function(data) {
        let countryData = { "name": data.name };
        neo = new DB();
        country = new Country(neo);
        country.insert(countryData)
            .then(resp => process.send(resp.msg) )
            .catch(err => process.send(err) )
    })
     .on("end", () => process.send("file read complete") );
});

./collection/country.js:

  Q = require('q');
  Country = function Country(neo) {
    this.country = "Country";  this.neo = neo;
  };

  Country.prototype.find = function find(filters) {
     query = 'MATCH (a:Country  { name: '${filters.name}' } )  RETURN {country:properties(a)}';
     return this.neo.run(query, filters).then(resp => resp);
  }

  Country.prototype.create = function create(data) {
    query = 'CREATE (ax:Country  { name: '${data.name}' } )  RETURN ax ';
    return this.neo.run(query, {}).then(resp => resp[0].properties).catch(err => err)
   }

   Country.prototype.insert = function insert(country) {
      filter = { name: country.name };
      return Q(this.find(filter))
        .then(resp => resp.length > 0 ? Q.resolve({ msg: 'country: [${country.name}] is already exist' }) : Q.resolve(this.create(country))  )
    .then(resp => resp)
    .catch(e => Q.reject(e));
   }

   module.exports = Country;

./common/driver.js

neo4j = require('neo4j-driver').v1;
function DB() {
   this.driver = neo4j.driver();   this.session = this.driver.session();
}

DB.prototype.run = function run(query, data) {
    return this.session.run(query, data)
    .then(response => response.records.map(
            record => record._fields[0] ?
            record._fields.length ? record._fields[0] : {} : {}
        ) ).catch(err => new Error(err) );
}

module.exports = DB;

Когда я запускаю index.js в терминале, в базе данных у меня есть 2 Afghanistan, 1 Aland, 2 Albania и 2 Bangladesh. Но мне нужна 1 Afghanistan, 1 Aland, 1 Albania и 1 Bangladesh в моей базе данных. Когда я анализирую код, чем обнаружил, что перед вставкой данных я проверяю данные (Country.prototype.find = function find(filters)), если он уже существует или нет, но он всегда возвращает пустой результат. Вот почему он вставляет несколько данных. Если я снова запустил index.js, то новые данные не будут добавлены в базу данных. Чтобы решить эту проблему, я попытался CQL:

  MERGE (c:Country  { name: '${data.name}' } )  RETURN c

В него вставляются уникальные данные, но он убивает так много времени. Затем я написал следующий код:

Событие (background-import-csv-file.js):

process.on("message", (file) => {
  stream = fs.createReadStream(file);
  csv
    .fromStream(stream, { headers: true })
    .on("data", function(data) {
        countryData = { "name": data.name };
        neo = new DB();
        country = new Country(neo);
        country.find(countryData);
        country.on('find', resp =>  resp.length > 0 ? Q.resolve({ msg: 'country: [${country.name}] is already exist' }) : Q.resolve(country.create(countryData))  );

        country.on('create', resp => console.log(resp) );
    })
    .on("end", () => process.send("file read complete") );
});

./collection/country.js:

 EventEmitter = require('events').EventEmitter;
 util = require('util');

 Country = function Country(neo) {
   this.neo = neo;  EventEmitter.call(this);
 };
 util.inherits(Country, EventEmitter);

 Country.prototype.find = function find(filters) {
    query = 'MATCH (a:Country  { name: '${filters.name}' } )  RETURN {country:properties(a)}';
    return this.neo.run(query, {}).then(resp => this.emit('find', resp));
 }

 Country.prototype.create = function create(data) {
    query = 'CREATE (ax:Country  { name: '${data.name}' } )  RETURN ax ';
    return this.neo.run(query, {}).then(resp => this.emit('create', resp[0].properties)).catch(err =>  err)
 }

И на этот раз он показывает тот же результат. Что мне не хватает? Любое предложение будет очень полезно.

NB: Я использую fast-csv для синтаксического анализа csv и Q для обещания.

  • 0
    Что значит "лебель"? Я не вижу очевидной причины, почему это нельзя сделать с помощью одного простого запроса Cypher.
Теги:
neo4j

2 ответа

1
Лучший ответ

Моя проблема заключалась в том, что в синтаксическом анализе csv он был настолько быстрым (управляемым событиями), что не дождался завершения вставки данных в базу данных. Поэтому я должен приостановить синтаксический анализ файлов, а затем возобновить его.

Я решаю свою проблему, используя следующий код:

На основе обещаний (background-import-csv-file.js):

cp = require('child_process');
csv = require('fast-csv');
Q = require('q');
DB = require("./common/driver");
Country = require('./collection/country');

process.on("message", (file) => {
  stream = fs.createReadStream(file);
  csvstream = csv
    .fromStream(stream, { headers: true })
    .on("data", function(data) {
       csvstream.pause();  // pause the csv file parsing
       countryData = { "name": data.name };
       neo = new DB();
       country = new Country(neo);
       country.insert(countryData)
         .then(resp => {
             process.send(resp.msg);
             neo.close();
             return csvstream.resume(); // after completing db process, resume 
         })
         .catch(err => {
             process.send(err);
             return csvstream.resume();  // if failed, then resume 
          });
    })
    .on("end", () => process.send("file read complete") );
 });
1

На самом деле я могу представить себе следующие решения:

  1. Измените сам файл CSV на языке программирования (например, node.js), чтобы удалить повторяющиеся строки с тем же именем.
  2. Добавьте уникальные ограничения CREATE CONSTRAINT ON (c:Country) ASSERT c.name IS UNIQUE
  3. Привлекайте промежуточное ПО, как очередь, чтобы предотвратить дублирование элементов, для этого вам необходимо определить собственную структуру сообщений и дублировать арифметику.

выше.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню