Отображение нескольких источников данных с разными именами полей для mongodb и mongoose (nodejs) - PullRequest
0 голосов
/ 31 мая 2018

Я работаю над сайтом, который будет содержать кучу данных из разных источников.Источники могут иметь большую часть одних и тех же данных (имеется некоторая избыточность), но поля в json могут варьироваться здесь и там.Эти источники взяты из REST API, все json.

Мой вопрос: как я могу сопоставить эти разные источники, используя схемы mongoose?Я хочу, чтобы это было как можно проще, как какая-то таблица, где мне просто нужно добавить имя поля нового источника и какое поле оно отображает в моей базе данных.Я использую экспресс / узел.

Вот пример двух источников и моей спецификации схемы.

Например.

Первый источник:

{
    "address":"123 abc st"
}

Второй источник:

{
    "addr":"123 abc st"
}

Моя схема:

{
    address:{
        type: String,
        required: true
}

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

Вы можете просто создать файл JSON для хранения сопоставления и получить его при сохранении вашего объекта.

Например, создайте файл JSON mappings.json:

{
  "addr": "address",
  "address": "address"
}

Затем проверьте в коде, соответствует ли свойство сопоставленному свойству.

let mappings = require('mappings.json');
let MyModel = requirse('models/myModel');

function createNewObjectFromInput (input, callback) {
   let options = {};
   for (let property in input) {
      if (input.hasOwnProperty(property) && mappings[property]) {
        options[mappings[property]] = input[property];
      }
   }
   let newObject = new MyModel(options);
   newObject.save(callback);
}

Комучтобы сделать вещи более надежными в нескольких источниках с возможными конфликтами свойств, вы можете создать такой файл JSON для каждого источника или просто отдельное сопоставление для каждого источника, например, так:

{
  "firstSource": { 
    "addr": "address
  },
  "secondSource": {
    "address": "address"
  }
}

И просто проверьте, какой источник вводитданные поступили от.

0 голосов
/ 01 июня 2018

То, что вам здесь нужно, это просто установить «виртуальное» поле с именем «псевдоним».Это позволяет вам использовать разные имена для поля, но они будут «переназначаться» на правильное имя, как определено в схеме.

В качестве полной демонстрации:

const { Schema } = mongoose = require('mongoose');

const uri = 'mongodb://localhost/test';

mongoose.Promise = global.Promise;
mongoose.set('debug', true);

const addressSchema = new Schema({
  address: { type: String, required: true }
});

// asssign a virtual to the "mapped" name
addressSchema.virtual('addr')
  .get(function() { return this.address })
  .set(function(v) { this.address = v });

const Address = mongoose.model('Adddress', addressSchema);

const log = data => console.log(JSON.stringify(data, undefined, 2));

(async function() {

  try {

    const conn = await mongoose.connect(uri);

    await Promise.all(Object.entries(conn.models).map(([k,m]) => m.remove()));

    // Raw documents don't work as the setter is ignored
    try {
      await Address.insertMany(
        [{ adddress: "123 abc st" },{ addr: "123 abc st" }]
      );
    } catch(e) {
      console.error(e);
    }

    // Creating via new works as expected
    let doc = new Address({ addr: "123 abc st" });
    log(doc);

    // Using Array.map over the objects to cast them works fine
    await Address.insertMany(
      [{ address: "123 abc str" },{ addr: "245 abc st" }]
        .map(Address)
    );

    let inserted = await Address.find();
    log({ inserted });

    mongoose.disconnect();

  } catch (e) {
    console.error(e)
  } finally {
    process.exit()
  }

})();

Что демонстрируетожидаемые результаты:

Mongoose: adddresses.remove({}, {})
{ ValidationError: Adddress validation failed: address: Path `address` is required.
    at ValidationError.inspect (/home/neillunn/projects/alias/node_modules/mongoose/lib/error/validation.js:56:24)
    at formatValue (util.js:430:38)
    at inspect (util.js:324:10)
    at format (util.js:191:12)
    at Console.warn (console.js:145:21)
    at /home/neillunn/projects/alias/index.js:37:15
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
  errors:
   { address:
      { ValidatorError: Path `address` is required.
    at new ValidatorError (/home/neillunn/projects/alias/node_modules/mongoose/lib/error/validator.js:25:11)
    at validate (/home/neillunn/projects/alias/node_modules/mongoose/lib/schematype.js:805:13)
    at /home/neillunn/projects/alias/node_modules/mongoose/lib/schematype.js:854:11
    at Array.forEach (<anonymous>)
    at SchemaString.SchemaType.doValidate (/home/neillunn/projects/alias/node_modules/mongoose/lib/schematype.js:814:19)
    at /home/neillunn/projects/alias/node_modules/mongoose/lib/document.js:1712:9
    at _combinedTickCallback (internal/process/next_tick.js:131:7)
    at process._tickCallback (internal/process/next_tick.js:180:9)
        message: 'Path `address` is required.',
        name: 'ValidatorError',
        properties: [Object],
        kind: 'required',
        path: 'address',
        value: undefined,
        reason: undefined,
        '$isValidatorError': true } },
  _message: 'Adddress validation failed',
  name: 'ValidationError' }
{
  "_id": "5b110aa571311d0a70cd3c88",
  "address": "123 abc st"
}
Mongoose: adddresses.insertMany([ { _id: 5b110aa571311d0a70cd3c89, address: '123 abc str', __v: 0 }, { _id: 5b110aa571311d0a70cd3c8a, address: '245 abc st', __v: 0 } ], {})
Mongoose: adddresses.find({}, { fields: {} })
{
  "inserted": [
    {
      "_id": "5b110aa571311d0a70cd3c89",
      "address": "123 abc str",
      "__v": 0
    },
    {
      "_id": "5b110aa571311d0a70cd3c8a",
      "address": "245 abc st",
      "__v": 0
    }
  ]
}

Чтобы пройти через это, все, что определено в дополнение к полю adddress в схеме, устанавливает другое виртуальное свойство в схеме:

addressSchema.virtual('addr')
  .get(function() { return this.address })
  .set(function(v) { this.address = v });

Это должно быть довольно просто, поскольку функция get() используется для чтения из address всякий раз, когда вы вместо этого фактически запрашиваете addr, а функция set(), конечно, применяется всякий раз, когда что-то пытается предоставить значение для addr и затем вместо этого помещает это значение в adddress.

Единственный улов в том, что эти "виртуалы" не применяются автоматически "везде", вы можете попытаться использовать их.Они работают находят с new Model(), но они не применяются автоматически ни к Model.create(), ни к Model.insertMany().

. В этом случае общий обходной путь, как показано ниже, это когда у вас есть список необработанных входных документов ".приведите «их», сначала запустив их через конструктор модели, как показано в листинге:

// Using Array.map over the objects to cast them works fine
await Address.insertMany(
  [{ address: "123 abc str" },{ addr: "245 abc st" }]
    .map(Address)
);

Затем данные будут правильно переписаны в address в обоих документах, которые будут вставлены, и этопроисходит до того, как сработает валидатор required.

В качестве альтернативы можно использовать свойство alias в схеме:

const addressSchema = new Schema({
  address: { type: String, required: true, alias: 'addr' }
});

Это на самом деле работает точно так же, без необходимостинаписать полный "виртуальный" методы.Вы можете считать это более коротким вариантом для выполнения того же действия, но вы, вероятно, должны знать, что на самом деле целью является «обратный», когда вы должны были определить «более короткое» имя в схеме и использовать «более длинное».для назначений.

Также вы можете добавить столько «виртуалов», сколько пожелаете, но вы можете использовать назначение alias «один раз» в определении схемы.Так что, если у вас разные источники данных, которые используют разные имена для хранения того, что вы хотите, то, вероятно, лучше использовать более длинную форму.

Оба документа описаны в документации по схеме Mongoose

0 голосов
/ 31 мая 2018

Используя метод model.discriminator (), вы можете попытаться создать наследование между вашими схемами.Сверьтесь с документацией Mongoose здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...