Así que desarrollé una aplicación con el marco de plumas. Tengo un enlace adjunto a un servicio de base de datos al que quiero acceder a datos de otro servicio. ¿Es esto posible y fácil? Quiero que ese servicio pueda acceder a varios archivos neDB. ¿Cómo hago esto?
'use strict';
module.exports = function(options) {
return function(hook) {
// access other db files here and get data
hook.data = {
putDataHere: newData
};
};
};
Si. Eche un vistazo al ejemplo de cómo obtener elementos relacionados . Básicamente, en su gancho puede acceder a otro servicio a través de hook.app.service('servicename')
y llamar al método que necesita. Para que el gancho espere, puede devolver una Promesa (que se resuelve con el objeto hook
) que convenientemente es lo que ya hacen todos los métodos de servicio:
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 Muchas gracias. Pensé que sería así de fácil, pero no pude encontrarlo en la documentación, debí haberlo perdido.
Ok, esta es una llamada de búsqueda que tengo antes del gancho (solo si necesita esa información)
Solo obtengo 25 pero hay cientos. Si elimino el límite, solo obtengo 5 artículos.
¿Qué está pasando y cómo consigo todo?
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 la opción que establezca para paginate.max
en la configuración. Es una protección para que alguien no pueda simplemente solicitar millones de registros de forma remota. En todos los adaptadores más nuevos, puede desactivar la paginación para obtener todos los registros como este :
return hook.app.service('data').find({
paginate: false,
query: { dataSet: dataSet }
}).then(data => {
// data is an array
});
Cuando hago eso, obtengo 0 registros. Cuando elimino la paginación: falso, obtengo 25.
¿ npm ls feathers-nedb
muestra v2.4.1? De lo contrario, es posible que deba actualizar su package.json
consecuencia.
Acabo de verificar que paginate: false
funciona con el siguiente ejemplo:
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);
Recibo 700 elementos registrados en la consola. ¿Agregó accidentalmente paginate: false
en la consulta en lugar de los parámetros principales?
Esto es lo que hice:
'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;
});
};
};
Todavía obtengo 0 resultados y 25 con la variable de paginación no allí y 5 resultados sin límite.
Sin embargo, lo hice funcionar con esto:
'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 puede ver, los resultados ya no están en page.data sino solo en la variable page.
Lección aprendida :)
Ah, y gracias @daffl por tu ayuda.
En el lado del cliente, no funciona. (la variable paginate: false,
).
Solo se pasa query
entre el cliente y el servidor. Intentaría evitar que un cliente solicite todas las entradas (si su base de datos tiene un millón de registros, matará tanto al servidor como al cliente). Si no hay forma de evitarlo, debe asignar un parámetro de consulta especial (por ejemplo, $paginate
) desde params.query
a params
en un enlace en el 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;
}
}
});
Entiendo la advertencia de no permitir la paginación en el lado del cliente, sin embargo, la herramienta que estoy creando es solo para que la ejecute localmente. Gracias de nuevo por todo.
@daffl Hola, estoy usando el código que ha publicado para recuperar las publicaciones que tiene un usuario.
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;
});
};
};
Pero esto hace que el servidor entre en un bucle infinito y la aplicación de nodo finalmente se bloquee.
Estoy usando MySQL como mi base de datos conectada por sequelize.
¿Qué estoy haciendo mal?
Configuré un gancho similar para que las publicaciones llenen el campo de usuario en función del campo postedBy
. Por lo que parece, el gancho de usuario activaría el gancho de publicación que a su vez activaría el gancho de usuario original y el bucle continúa dando como resultado un bucle infinito y un desbordamiento de memoria.
Cualquier idea sobre cómo rellenar solo un elemento relacionado superficial, es decir, el gancho extraería solo los elementos relacionados solo en el primer nivel.
@daffl Tu idea es genial, aunque el código no funcionó.
Tuve que cambiar hook.paginate a hook.params.paginate para que funcionara.
E hice un pequeño cambio para que puedas enviar lo que quieras allí.
para que pueda $ paginar: {valor: falso} para deshabilitar la paginación o
$ paginate: {value: {default: 100, max: 2000}} para anular la paginación
app.service('data').before({
find(hook) {
if(hook.params.query.$paginate) {
hook.params.paginate = hook.params.query.$paginate.value;
delete hook.params.query.$paginate;
}
}
});
Una cosa más a considerar es que, cuando la paginación está deshabilitada, los datos no están en res.data sino en la propia res.
@ fortunes-technology Tienes razón. Actualicé mi fragmento de código. Esto debería 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;
}
}
});
Creo que si $ paginate se establece en falso (que es el objetivo de este gancho, para deshabilitarlo ...), el if también será falso. Quizás
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;
}
}
});
Hola. ¿Alguien podría decirme si los servicios de plumas tienen la funcionalidad findOne o cómo implementarla? ¡Gracias!
cc @daffl
Un findOne
es solo un find
con un $limit
de 1:
app.service('myservice').find({ query: { name: 'test', $limit: 1 } })
.then(page => page.data[0])
.then(result => console.log('Got', result);
@daffl Pregunté porque mangosta tiene findOne y sugerí que no buscara en toda la colección de descanso si ya había encontrado algo. Entonces, pensé en findOne como algo más inteligente que buscar con límite = 1 ... Por eso pregunté.
Normalmente hago esto para una búsqueda rápida.
const employee = (await context.app.service('employees').find({ query: { userId: user.id }, paginate: false }))[0];
Acabo de crear un complemento para un método .findOne()
: feathers-findone
No pude encontrar ningún ejemplo sobre cómo agregar la solución alternativa $ paginate para el cliente. Así que creé un gancho anterior que se ejecuta desde el archivo app.hooks.js con algunas modificaciones:
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;
}
};
};
¿Cómo haría para escribir una unidad o una prueba de integración para esto?
así que si tengo lo siguiente en mi gancho
const records = getItems(context);
records.authors = await context.app.service('users') .find({ query: { _id: { $in: records.authorIds } } }, context.params);
¿Cómo puedo "burlarme" del servicio context.app.service en mi prueba unitaria?
¿Necesito agregarlo a mi objeto contextBefore?
contextBefore = {
type: 'before',
params: { provider: 'socketio', user: { _id: 1 } },
data: {
_id: 1,
},
};
Estoy usando la prueba unitaria generada automáticamente por el generador de plumas más.
https://generator.feathers-plus.com/get-started/#unit -test-for-a-hook
¿O debería utilizar una prueba de integración en su lugar?
Hace algún tiempo que tomé la ruta de la burla. Creo que es una muy mala idea. Eventualmente tendrás que burlarte más y más de Feathers. No hay garantía de que sus simulacros funcionen como lo hacen las plumas y puede obtener falsos negativos, como lo hice yo.
Instalar una aplicación Feathers es muy rápido, así que usa Feathers en lugar de simulacros. Así es como se valora la prueba cli +.
Escribí un artículo que se refiere a esto. https://medium.com/feathers-plus/automatic-tests-with-feathers-plus-cli-4844721a29cf
gracias Eddyy, lo he visto, gran artículo, realmente me ayudó.
Estaba luchando sobre cómo agregar la aplicación a mi objeto de contexto, ¡pero creo que finalmente lo resolví!
const app = feathers();
contextBefore = {
type: 'before',
params: { provider: 'socketio', user: { _id: 1 } },
data: {
_id: 1,
},
app,
};
Luego tuve que modificar la prueba para que usara 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,
});
});
¿Es esa la forma correcta de hacerlo o hay una forma mejor?
Se ve bien
@ fortunes-technology Tienes razón. Actualicé mi fragmento de código. Esto debería 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; } } });
puede usar query $ limit: null para omitir también
Comentario más útil
Si. Eche un vistazo al ejemplo de cómo obtener elementos relacionados . Básicamente, en su gancho puede acceder a otro servicio a través de
hook.app.service('servicename')
y llamar al método que necesita. Para que el gancho espere, puede devolver una Promesa (que se resuelve con el objetohook
) que convenientemente es lo que ya hacen todos los métodos de servicio: