Então, desenvolvi um aplicativo com a estrutura de penas. Eu tenho um gancho anexado a um serviço de banco de dados que desejo acessar dados de outro serviço. Isso é possível e fácil? Quero que esse serviço possa acessar vários arquivos neDB. Como eu faço isso?
'use strict';
module.exports = function(options) {
return function(hook) {
// access other db files here and get data
hook.data = {
putDataHere: newData
};
};
};
sim. Dê uma olhada no exemplo de como buscar itens relacionados . Basicamente, em seu gancho você pode acessar outro serviço via hook.app.service('servicename')
e chamar o método que você precisa. Para que o gancho aguarde, você pode retornar uma promessa (que se resolve com o objeto hook
), que é convenientemente o que todos os métodos de serviço já fazem:
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 Muito obrigado. Achei que seria assim tão fácil, mas não consegui encontrar na documentação, devo ter perdido.
Ok, então esta é uma chamada de busca que eu tenho antes do gancho (apenas se você precisar dessa informação)
Estou recebendo apenas 25, mas existem centenas. Se eu remover o limite, recebo apenas 5 itens.
O que está acontecendo e como faço para obter tudo?
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;
});
};
};
Depende de qual opção você definiu para paginate.max
na configuração. É uma proteção para que alguém não possa simplesmente solicitar milhões de registros remotamente. Em todos os adaptadores mais recentes, você pode desligar a paginação para obter todos os registros assim :
return hook.app.service('data').find({
paginate: false,
query: { dataSet: dataSet }
}).then(data => {
// data is an array
});
Quando faço isso, obtenho 0 registros. Quando removo a paginação: falso, obtenho 25.
npm ls feathers-nedb
mostra a v2.4.1? Caso contrário, você terá que atualizar seu package.json
acordo.
Acabei de verificar que paginate: false
funciona com o seguinte exemplo:
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);
Estou recebendo 700 itens registrados no console. Você acidentalmente adicionou paginate: false
à consulta em vez dos parâmetros principais?
Isso é o que eu fiz:
'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;
});
};
};
Ainda obtém 0 resultados e 25 com a variável de paginação ausente e 5 resultados sem limite.
No entanto, consegui funcionar com isto:
'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;
});
};
};
Como você pode ver, os resultados não estão mais em page.data, mas apenas na variável de página.
Lição aprendida :)
Oh e obrigado @daffl por sua ajuda.
Do lado do cliente, não funciona. (a variável paginate: false,
).
Apenas query
é passado entre o cliente e o servidor. Eu tentaria evitar que um cliente solicitasse todas as entradas (se seu banco de dados tiver um milhão de registros, ele matará ambos, o servidor e o cliente). Se não houver maneira de contornar isso, você terá que mapear um parâmetro de consulta especial (por exemplo, $paginate
) de params.query
em params
em um gancho no servidor:
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;
}
}
});
Eu entendo o aviso de não permitir a paginação no lado do cliente, no entanto, a ferramenta que estou fazendo é apenas para eu executar localmente. Obrigado novamente por tudo.
@daffl Olá, estou usando o código que você postou para recuperar as postagens de um usuário.
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;
});
};
};
Mas isso faz com que o servidor entre em um loop infinito e o aplicativo de nó finalmente travar.
Estou usando o MySQL como meu banco de dados conectado pelo sequelize.
O que estou fazendo errado?
Eu tinha configurado um gancho semelhante para postagens para preencher o campo do usuário com base no campo postedBy
. Assim, ao que parece, o gancho do usuário acionaria o gancho posterior que, por sua vez, acionaria o gancho do usuário original e o loop continuaria resultando em um loop infinito e estouro de memória.
Qualquer ideia de como preencher apenas um item relacionado superficial, ou seja, o gancho puxaria apenas os itens relacionados apenas no primeiro nível.
@daffl Sua ideia é incrível, embora o código não funcione.
Tive que alterar hook.paginate para hook.params.paginate para fazê-lo funcionar.
E eu fiz uma pequena alteração para que você possa enviar o que quiser.
então você pode $ paginate: {value: false} para desativar a paginação ou
$ paginate: {value: {default: 100, max: 2000}} para substituir a paginação
app.service('data').before({
find(hook) {
if(hook.params.query.$paginate) {
hook.params.paginate = hook.params.query.$paginate.value;
delete hook.params.query.$paginate;
}
}
});
Mais uma coisa a se considerar é que, quando a paginação está desabilitada, os dados não estão em res.data, mas em si mesmo.
@ fortunes-technology Você está certo. Eu atualizei meu trecho de código. Isso deve funcionar:
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;
}
}
});
Eu acho que se $ paginate estiver definido como falso (que é o ponto deste gancho, para desabilitá-lo ...), o if também será falso. Pode ser
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;
}
}
});
Olá. Alguém poderia me dizer se os serviços de penas têm a funcionalidade findOne ou como implementá-la? Obrigado!
cc @daffl
A findOne
é apenas find
com $limit
de 1:
app.service('myservice').find({ query: { name: 'test', $limit: 1 } })
.then(page => page.data[0])
.then(result => console.log('Got', result);
@daffl Eu perguntei porque o mongoose tem findOne e eu sugeri que ele não procure em toda a coleção de resto se algo já foi encontrado. Então, pensei em findOne como algo mais inteligente do que pesquisar com limit = 1 ... É por isso que perguntei.
Normalmente faço isso para uma localização rápida:
const employee = (await context.app.service('employees').find({ query: { userId: user.id }, paginate: false }))[0];
Acabei de criar um plugin para um método .findOne()
: penas-findone
Não consegui encontrar nenhum exemplo de como adicionar a solução alternativa $ paginate para o cliente. Então, criei um hook before que é executado a partir do arquivo app.hooks.js com algumas modificações:
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;
}
};
};
Como você escreveria um teste de unidade ou integração para isso?
então, se eu tiver o seguinte no meu gancho
const records = getItems(context);
records.authors = await context.app.service('users') .find({ query: { _id: { $in: records.authorIds } } }, context.params);
como faço para "simular" o context.app.service em meu teste de unidade?
preciso adicioná-lo ao meu objeto contextBefore?
contextBefore = {
type: 'before',
params: { provider: 'socketio', user: { _id: 1 } },
data: {
_id: 1,
},
};
estou usando o teste de unidade gerado automaticamente pelo gerador de penas plus.
https://generator.feathers-plus.com/get-started/#unit -test-for-a-hook
ou devo usar um teste de integração em vez disso?
Eu segui a rota da zombaria há algum tempo. Eu acho que é uma ideia muito ruim. Você eventualmente terá que zombar mais e mais das penas. Não há nenhuma garantia de que suas simulações funcionem como as penas e você pode obter falsos negativos, como eu.
Instanciar um aplicativo Feathers é muito rápido, então use Feathers em vez de simulações. É assim que se faz a abordagem do teste cli +.
Escrevi um artigo que se refere a isso. https://medium.com/feathers-plus/automatic-tests-with-feathers-plus-cli-4844721a29cf
obrigado eddyy, eu vi esse, ótimo artigo, realmente ajudou.
Eu estava tendo dificuldades em como adicionar o aplicativo ao meu objeto de contexto, mas acabei descobrindo, eu acho!
const app = feathers();
contextBefore = {
type: 'before',
params: { provider: 'socketio', user: { _id: 1 } },
data: {
_id: 1,
},
app,
};
Então eu tive que alterar o teste para que ele usasse 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,
});
});
Essa é a maneira certa de fazer isso ou existe uma maneira melhor?
Parece bom
@ fortunes-technology Você está certo. Eu atualizei meu trecho de código. Isso deve funcionar:
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; } } });
pode usar a consulta $ limit: null para ignorar também
Comentários muito úteis
sim. Dê uma olhada no exemplo de como buscar itens relacionados . Basicamente, em seu gancho você pode acessar outro serviço via
hook.app.service('servicename')
e chamar o método que você precisa. Para que o gancho aguarde, você pode retornar uma promessa (que se resolve com o objetohook
), que é convenientemente o que todos os métodos de serviço já fazem: