Итак, я разработал приложение с фреймворком из перьев. У меня есть крючок, подключенный к службе базы данных, и я хочу получить доступ к данным из другой службы. Возможно ли это и легко? Я хочу, чтобы эта служба имела доступ к нескольким файлам neDB. Как мне это сделать?
'use strict';
module.exports = function(options) {
return function(hook) {
// access other db files here and get data
hook.data = {
putDataHere: newData
};
};
};
да. Посмотрите на пример, как получить связанные элементы . По сути, в вашем хуке вы можете получить доступ к другой службе через hook.app.service('servicename')
и вызвать нужный вам метод. Чтобы перехватчик ждал, вы можете вернуть обещание (которое разрешается с помощью объекта hook
), что удобно для всех методов службы:
module.exports = function(options) {
return function(hook) {
return hook.app.service('otherservice').find({
query: { name: 'David' }
}).then(page => {
const davids = page.data;
hook.data.davids = davids;
// Or you can replace all the data with
hook.data = { davids };
// IMPORTANT: always return the `hook` object in the end
return hook;
});
};
};
@daffl Большое спасибо. Я подумал, что это будет так просто, но не нашел в документации, наверное, пропустил.
Хорошо, это вызов поиска, который у меня есть перед крючком (просто если вам нужна эта информация)
Я получаю только 25, но их уже сотни. Если я сниму ограничение, я получу только 5 предметов.
Что происходит и как мне все получить?
module.exports = function(options) {
return function(hook) {
const dataSet = hook.params.query.dataSet;
const userVector = hook.params.query.userVector;
return hook.app.service('data').find({
query: { dataSet: dataSet, $limit:2000 }
}).then(page => {
// lots of magic here
//console.log(page.data);
hook.result = page.data;
return hook;
});
};
};
Это зависит от того, какой параметр вы установили для paginate.max
в конфигурации. Это гарантия того, что кто-то не может просто запросить миллионы записей удаленно. Во всех новых адаптерах вы можете отключить разбиение на страницы, чтобы получить все записи следующим образом :
return hook.app.service('data').find({
paginate: false,
query: { dataSet: dataSet }
}).then(data => {
// data is an array
});
Когда я это сделаю, у меня будет 0 записей. Когда я удаляю разбиение на страницы: false, я получаю 25.
npm ls feathers-nedb
показывает v2.4.1? В противном случае вам, возможно, придется соответствующим образом обновить свой package.json
.
Я только что проверил, что paginate: false
работает со следующим примером:
const feathers = require('feathers');
const rest = require('feathers-rest');
const socketio = require('feathers-socketio');
const hooks = require('feathers-hooks');
const nedb = require('feathers-nedb');
const bodyParser = require('body-parser');
const handler = require('feathers-errors/handler');
const NeDB = require('nedb');
// A Feathers app is the same as an Express app
const app = feathers();
const db = new NeDB({
filename: './data/messages.db',
autoload: true
});
// Parse HTTP JSON bodies
app.use(bodyParser.json());
// Parse URL-encoded params
app.use(bodyParser.urlencoded({ extended: true }));
// Register hooks module
app.configure(hooks());
// Add REST API support
app.configure(rest());
// Configure Socket.io real-time APIs
app.configure(socketio());
// Register our memory "users" service
app.use('/todos', nedb({
Model: db,
paginate: {
default: 20,
max: 50
}
}));
// Register a nicer error handler than the default Express one
app.use(handler());
const promises = [];
for(let i = 0; i < 700; i++) {
promises.push(app.service('todos').create({ text: `Item #${i}`}));
}
Promise.all(promises).then(function() {
app.service('todos').find({
paginate: false,
query: {}
}).then(data => console.log(data));
});
// Start the server
app.listen(3333);
Я получаю 700 записей, зарегистрированных в консоли. Вы случайно не добавили в запрос paginate: false
вместо основных параметров?
Вот что я сделал:
'use strict';
module.exports = function(options) {
return function(hook) {
const dataSet = hook.params.query.dataSet;
const userVector = hook.params.query.userVector;
return hook.app.service('data').find({
paginate: false,
query: { dataSet: dataSet, $limit:2000 }
}).then(page => {
// lots of magic here
console.log(page.data);
hook.result = page.data;
return hook;
});
};
};
По-прежнему получаются 0 результатов, 25 с отсутствующей переменной разбивки на страницы и 5 результатов без ограничений.
Тем не менее, я работал с этим:
'use strict';
module.exports = function(options) {
return function(hook) {
const dataSet = hook.params.query.dataSet;
const userVector = hook.params.query.userVector;
return hook.app.service('data').find({
paginate: false,
query: { dataSet: dataSet }
}).then(page => {
// lots of magic here
console.log(page);
hook.result = page;
return hook;
});
};
};
Как видите, результатов больше нет в page.data, а просто в переменной страницы.
Урок выучен :)
Ох, и спасибо @daffl за вашу помощь.
На стороне клиента это не работает. (переменная paginate: false,
).
Между клиентом и сервером передается только query
. Я бы постарался не позволять клиенту запрашивать все операции (если в вашей базе данных миллион записей, это убьет и сервер, и клиента). Если нет никакого способа обойти это, вам нужно отобразить специальный параметр запроса (например, $paginate
) из params.query
в params
в ловушке на сервере:
app.service('data').before({
find(hook) {
if(hook.params.query && hook.params.query.$paginate) {
hook.params.paginate = hook.params.query.$paginate === 'false' || hook.params.query.$paginate === false;
delete hook.params.query.$paginate;
}
}
});
Я понимаю предупреждение о запрете пагинации на стороне клиента, однако созданный мной инструмент предназначен только для локального запуска. Еще раз спасибо за все.
@daffl Привет, я использую опубликованный вами код для получения сообщений,
module.exports = function(options) {
return function(hook) {
// hook.getPosts = true;
const id = hook.result.id;
console.log("id");
return hook.app.service('posts').find({
paginate: false,
query: { postedBy: id }
}).then(function(posts){
console.log("posts");
// Set the posts on the user property
hook.result.posts = posts.data;
// Always return the hook object or `undefined`
return hook;
});
};
};
Но это приводит к тому, что сервер заходит в бесконечный цикл, и приложение узла в конечном итоге дает сбой.
Я использую MySQL в качестве моей БД, подключенной с помощью sequelize.
Что я делаю неправильно?
Я установил аналогичный хук для сообщений, чтобы заполнить пользовательское поле на основе поля postedBy
. Похоже, что обработчик пользователя вызовет обработчик post, который, в свою очередь, вызовет исходный обработчик пользователя, и цикл продолжится, что приведет к бесконечному циклу и переполнению памяти.
Любые идеи, как заполнить только неглубокий связанный элемент, т.е. крючок будет тянуть только связанные элементы только на первом уровне.
@daffl Идея у вас
Мне пришлось изменить hook.paginate на hook.params.paginate, чтобы он заработал.
И я внес небольшое изменение, чтобы вы могли отправлять туда все, что хотите.
так что вы можете $ paginate: {value: false} отключить разбиение на страницы или
$ paginate: {value: {default: 100, max: 2000}}, чтобы переопределить разбиение на страницы
app.service('data').before({
find(hook) {
if(hook.params.query.$paginate) {
hook.params.paginate = hook.params.query.$paginate.value;
delete hook.params.query.$paginate;
}
}
});
Еще одна вещь, которую следует учитывать, - когда разбивка на страницы отключена, данные находятся не в res.data, а в самом res.
@ fortunes-technology Вы правы. Я обновил свой фрагмент кода. Это должно работать:
app.service('data').before({
find(hook) {
if(hook.params.query && hook.params.query.$paginate) {
hook.params.paginate = hook.params.query.$paginate === 'false' || hook.params.query.$paginate === false;
delete hook.params.query.$paginate;
}
}
});
Я думаю, что если для $ paginate установлено значение false (что является целью этого хука, чтобы отключить его ...), if тоже будет ложным. Может быть
app.service('data').before({
find(hook) {
if(hook.params.query && hook.params.query.hasOwnProperty('$paginate')) {
hook.params.paginate = hook.params.query.$paginate === 'false' || hook.params.query.$paginate === false;
delete hook.params.query.$paginate;
}
}
});
Всем привет. Может ли кто-нибудь сказать мне, есть ли у сервисов пера функциональность findOne или как ее реализовать? Спасибо!
cc @daffl
findOne
- это просто find
с $limit
равным 1:
app.service('myservice').find({ query: { name: 'test', $limit: 1 } })
.then(page => page.data[0])
.then(result => console.log('Got', result);
@daffl Я спросил, потому что у mongoose есть findOne, и я предложил, чтобы он не просматривал всю остальную коллекцию, если что-то уже было найдено. Итак, я подумал о findOne как о чем-то более умном, чем поиск с limit = 1 ... Вот почему я спросил.
Обычно я делаю это для быстрого findOne:
const employee = (await context.app.service('employees').find({ query: { userId: user.id }, paginate: false }))[0];
Я только что сделал плагин для метода .findOne()
: перья-findone
Я не смог найти ни одного примера того, как добавить обходной путь $ paginate для клиента. Итак, я создал обработчик before, который запускается из файла app.hooks.js с некоторыми изменениями:
module.exports = function () {
return context => {
if (context.params.query && hook.params.query.hasOwnProperty('$paginate')) {
context.params.paginate = context.params.query.$paginate === 'false' || context.params.query.$paginate === false;
delete context.params.query.$paginate;
}
};
};
Как бы вы написали для этого модульный или интеграционный тест?
То же, что и любой другой тест для Feathers .
так что если у меня на крючке есть следующее
const records = getItems(context);
records.authors = await context.app.service('users') .find({ query: { _id: { $in: records.authorIds } } }, context.params);
как "имитировать" context.app.service в моем модульном тесте?
мне нужно добавить его в мой объект contextBefore?
contextBefore = {
type: 'before',
params: { provider: 'socketio', user: { _id: 1 } },
data: {
_id: 1,
},
};
Я использую модульный тест, автоматически сгенерированный из генератора перьев плюс.
https://generator.feathers-plus.com/get-started/#unit -test-for-a-hook
или лучше использовать интеграционный тест?
Некоторое время назад я пошел путем насмешек. Я думаю, это очень плохая идея. Со временем вам придется издеваться над перьями все больше и больше. Нет гарантии, что ваши макеты работают как перья, и вы можете получить ложноотрицательные результаты, как это сделал я.
Создание приложения Feathers выполняется очень быстро, поэтому используйте Feathers вместо имитаций. Вот как проходит оценка теста cli +.
Я написал статью об этом. https://medium.com/feathers-plus/automatic-tests-with-feathers-plus-cli-4844721a29cf
спасибо eddyy, я видел ту, отличная статья, действительно помогла.
Я боролся с тем, как добавить приложение к моему объекту контекста, но в конце концов, я думаю!
const app = feathers();
contextBefore = {
type: 'before',
params: { provider: 'socketio', user: { _id: 1 } },
data: {
_id: 1,
},
app,
};
Затем мне пришлось изменить тест, чтобы он использовал async.
it('patch test', async () => {
contextBefore.app.use('users', {
async find() {
return { data: [ { expectedResultObj1 }, { expectedResultObj2 } ] };
}
});
contextBefore.data = {
_id: 1,
};
assert(true);
await hookToTest()(contextBefore);
assert.deepEqual(contextBefore.data, {
_id: 1,
expectedResultObject1,
expectedResultObject2,
});
});
Это правильный способ сделать это или есть лучший способ?
Выглядит неплохо
@ fortunes-technology Вы правы. Я обновил свой фрагмент кода. Это должно работать:
app.service('data').before({ find(hook) { if(hook.params.query && hook.params.query.$paginate) { hook.params.paginate = hook.params.query.$paginate === 'false' || hook.params.query.$paginate === false; delete hook.params.query.$paginate; } } });
также можно использовать query $ limit: null для обхода
Самый полезный комментарий
да. Посмотрите на пример, как получить связанные элементы . По сути, в вашем хуке вы можете получить доступ к другой службе через
hook.app.service('servicename')
и вызвать нужный вам метод. Чтобы перехватчик ждал, вы можете вернуть обещание (которое разрешается с помощью объектаhook
), что удобно для всех методов службы: