Я работаю над веб-сайтом, на котором будут размещены данные из разных источников. Источники могут иметь в основном одни и те же данные (есть некоторая избыточность), но поля в json могут варьироваться здесь и там. Эти источники взяты из REST API, все json.
Мой вопрос: как я могу сопоставить эти разные источники с помощью схем мангуста? Я хочу, чтобы это было как можно проще, как какая-то таблица, в которую мне просто нужно добавить имя поля нового источника и какое поле оно отображается в моей базе данных. Я использую экспресс / узел.
Вот пример двух источников и моя спецификация схемы.
Например.
Первый источник:
{
"address":"123 abc st"
}
Второстепенный источник:
{
"addr":"123 abc st"
}
Моя схема:
{
address:{
type: String,
required: true
}





Используя метод model.discriminator (), вы можете попытаться создать наследование между вашими схемами. Проверьте документацию Mongoose здесь.
Вы можете просто создать файл JSON для хранения сопоставления и получить его при сохранении вашего объекта.
Например, создайте файл JSON mappings.json:
{
"addr": "address",
"address": "address"
}
Затем проверьте в коде, соответствует ли свойство сопоставленному свойству.
let mappings = require('mappings.json');
let MyModel = require('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"
}
}
И просто проверьте, из какого источника пришли ваши входные данные.
Похоже, что вам нужно просто создать «виртуальное» поле с именем «псевдоним». Это позволяет вам использовать разные имена для поля, но они будут «переназначены» на правильное имя, как определено в схеме.
В качестве полной демонстрации:
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.info(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.
Я пытаюсь пойти по виртуальному пути, но безуспешно. это то, что у меня есть, и я попытался передать параметр через set, а затем установить для поля его значение, но это тоже не работает. Я знаю, что делаю здесь что-то не так. Не могли бы вы подробнее рассказать о виртуальном методе выполнения того, что я хочу делать? globalMarketCap .virtual('market_cap') .get(function(){ return this.get('total_market_cap_usd'); }) .set(function(){ return this.set('total_market_cap_usd'); });
@Salx В вопросе есть "рабочие" образцы кода. Все, что вам нужно сделать, это запустить код, чтобы убедиться, что подход работает. Под вопросом будет результат выполнения кода. Так что вам действительно нечего "пробовать". Просто «сделайте», запустите код и «сделайте» точно то же самое, а не то, что вы придумываете. Ваш «вопрос» касается addr и address, и это рабочий ответ, который вы получите. Научитесь Примите ваши ответы, где они четко отвечают на фактически заданный вопрос.
Есть ли в предоставленном ответе что-то, что, по вашему мнению, не отвечает на ваш вопрос? Если да, то прокомментируйте ответ, чтобы уточнить, что именно нужно решить, а что нет. Если он действительно отвечает на вопрос, который вы задали, обратите внимание на Примите ваши ответы на вопросы, которые вы задаете.