Feathers: Assoziationen abrufen

Erstellt am 8. Aug. 2016  ·  30Kommentare  ·  Quelle: feathersjs/feathers

Also habe ich eine App mit dem Federn-Framework entwickelt. Ich habe einen Hook an einen Datenbankdienst angehängt, über den ich auf Daten von einem anderen Dienst zugreifen möchte. Ist das möglich und einfach? Ich möchte, dass dieser Dienst auf mehrere neDB-Dateien zugreifen kann. Wie mache ich das?

'use strict';

module.exports = function(options) {
  return function(hook) {

    // access other db files here and get data

    hook.data = {
        putDataHere: newData
    };
  };
};

Hilfreichster Kommentar

Ja. Sehen Sie sich das Beispiel an, wie verwandte Elemente abgerufen werden . Grundsätzlich können Sie in Ihrem Hook über hook.app.service('servicename') auf einen anderen Dienst zugreifen und die gewünschte Methode aufrufen. Damit der Hook wartet, können Sie ein Promise zurückgeben (das mit dem hook Objekt aufgelöst wird), was praktischerweise alle Servicemethoden bereits tun:

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;
    });
  };
};

Alle 30 Kommentare

Ja. Sehen Sie sich das Beispiel an, wie verwandte Elemente abgerufen werden . Grundsätzlich können Sie in Ihrem Hook über hook.app.service('servicename') auf einen anderen Dienst zugreifen und die gewünschte Methode aufrufen. Damit der Hook wartet, können Sie ein Promise zurückgeben (das mit dem hook Objekt aufgelöst wird), was praktischerweise alle Servicemethoden bereits tun:

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 Vielen Dank. Ich dachte, es wäre so einfach, konnte es aber nicht in der Dokumentation finden, ich muss es übersehen haben.

Ok, das ist ein Suchaufruf, den ich vor dem Hook habe (nur wenn Sie diese Informationen benötigen)

Ich bekomme nur 25, aber es sind Hunderte. Wenn ich das Limit aufhebe, bekomme ich nur 5 Artikel.

Was ist los und wie bekomme ich alles?

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;
    });
  };
};

Es hängt davon ab, welche Option Sie für paginate.max in der Konfiguration festgelegt haben. Es ist ein Schutz, damit jemand nicht einfach aus der Ferne Millionen von Datensätzen anfordern kann. In allen neueren Adaptern können Sie die Paginierung deaktivieren, um alle Datensätze wie folgt zu erhalten:

return hook.app.service('data').find({
      paginate: false,
      query: { dataSet: dataSet }
    }).then(data => {
      // data is an array
    });

Wenn ich das tue, bekomme ich 0 Datensätze. Wenn ich die Paginierung entferne: false, bekomme ich 25.

Zeigt npm ls feathers-nedb v2.4.1 an? Wenn nicht, müssen Sie möglicherweise Ihre package.json entsprechend aktualisieren.

└── [email protected]

Ich habe gerade überprüft, dass paginate: false mit dem folgenden Beispiel funktioniert:

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);

Ich erhalte 700 Elemente, die in der Konsole protokolliert werden. Haben Sie versehentlich paginate: false anstelle der Hauptparameter in die Abfrage eingefügt?

Das habe ich gemacht:

'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;
    });
  };
};

Erhalten Sie immer noch 0 Ergebnisse und 25 mit nicht vorhandener Paginierungsvariable und 5 Ergebnisse ohne Begrenzung.

Ich habe es jedoch damit zum Laufen gebracht:

'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;
    });
  };
};

Wie Sie sehen, befinden sich die Ergebnisse nicht mehr in page.data, sondern nur noch in der Seitenvariablen.

Lektion gelernt :)

Oh und danke @daffl für deine Hilfe.

Auf der Clientseite funktioniert es nicht. (die Variable paginate: false, ).

Zwischen dem Client und dem Server wird nur query übergeben. Ich würde versuchen zu vermeiden, dass ein Client alle Einträge anfordert (wenn Ihre Datenbank eine Million Datensätze hat, wird sie sowohl den Server als auch den Client töten). Wenn es nicht darum geht, müssen Sie einen speziellen Abfrageparameter (zB $paginate ) von params.query in params in einem Hook auf dem Server abbilden:

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;
    }
  }
});

Ich verstehe die Warnung, dass die Paginierung auf der Clientseite nicht zugelassen wird, aber das Tool, das ich erstelle, ist nur für mich, um lokal ausgeführt zu werden. Danke nochmal für alles.

@daffl Hallo, ich verwende den von Ihnen geposteten Code, um Beiträge eines Benutzers abzurufen.

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;
    });
  };
};

Dies führt jedoch dazu, dass der Server in eine Endlosschleife geht und die Node-App letztendlich abstürzt.

Ich verwende MySQL als meine DB, die durch Sequelize verbunden ist.

Was mache ich falsch?

Aktualisieren

Ich hatte einen ähnlichen Hook für Beiträge eingerichtet, um das Benutzerfeld basierend auf dem Feld postedBy füllen. Es scheint also, dass der Benutzer-Hook den Post-Hook auslösen würde, der wiederum den ursprünglichen Benutzer-Hook auslösen würde, und die Schleife wird fortgesetzt, was zu einer Endlosschleife und einem Speicherüberlauf führt.

Irgendwelche Ideen, wie man nur ein flaches verwandtes Element auffüllt, dh der Haken würde nur die verwandten Elemente auf nur der ersten Ebene ziehen.

@daffl Ihre Idee ist großartig, obwohl der Code nicht funktioniert hat.
Ich musste Hook.paginate in Hook.params.paginate ändern, damit es funktioniert.
Und ich habe eine kleine Änderung vorgenommen, damit Sie dorthin senden können, was Sie wollen.
also können Sie $paginate : {value: false} um die Paginierung zu deaktivieren oder
$paginate: { value: {default: 100, max: 2000}} um die Paginierung zu überschreiben

app.service('data').before({ find(hook) { if(hook.params.query.$paginate) { hook.params.paginate = hook.params.query.$paginate.value; delete hook.params.query.$paginate; } } });

Eine weitere zu berücksichtigende Sache ist, dass sich die Daten bei deaktivierter Paginierung nicht in res.data, sondern in res selbst befinden.

@fortunes-technology Sie haben Recht. Ich habe mein Code-Snippet aktualisiert. Das sollte funktionieren:

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;
    }
  }
});

Ich denke, wenn $paginate auf false gesetzt ist (was der Sinn dieses Hooks ist, um es zu deaktivieren ... ), wird auch das if false sein. Könnte sein

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;
    }
  }
});

Hi. Könnte mir jemand sagen, ob Federn-Dienste die findOne-Funktionalität haben oder wie man sie implementiert? Danke!
cc @daffl

Ein findOne ist nur ein find mit einem $limit von 1:

app.service('myservice').find({ query: { name: 'test', $limit: 1 } })
 .then(page => page.data[0])
 .then(result => console.log('Got', result);

@daffl Ich habe gefragt, weil Mungo findOne hat und ich habe vorgeschlagen, dass es nicht die gesamte Restsammlung durchsucht, wenn bereits etwas gefunden wurde. Also dachte ich über findOne als etwas schlaueres als Suche mit limit=1... Deshalb habe ich nachgefragt.

Normalerweise mache ich dies für ein schnelles findOne:

const employee = (await context.app.service('employees').find({ query: { userId: user.id }, paginate: false }))[0];

Ich habe gerade ein Plugin für eine .findOne() Methode erstellt: Federn-findone

Ich konnte kein Beispiel finden, wie die Problemumgehung von $paginate für den Client hinzugefügt wird. Also habe ich einen Vorher-Hook erstellt, der mit einigen Modifikationen von der Datei app.hooks.js ausgeführt wird:

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;
    }
  };
};

Wie würden Sie dafür einen Unit- oder Integrationstest schreiben?

also wenn ich folgendes in meinem Hook habe

const records = getItems(context);
records.authors = await context.app.service('users') .find({ query: { _id: { $in: records.authorIds } } }, context.params);

Wie "mock" ich den context.app.service in meinem Komponententest?

muss ich es zu meinem contextBefore-Objekt hinzufügen?

contextBefore = { type: 'before', params: { provider: 'socketio', user: { _id: 1 } }, data: { _id: 1, }, };

Ich verwende den Unit-Test-Auto, der vom Federn-Plus-Generator generiert wird.
https://generator.feathers-plus.com/get-started/#unit -test-for-a-hook

oder sollte ich stattdessen einen Integrationstest verwenden?

Ich bin vor einiger Zeit den Spottweg gegangen. Ich denke, es ist eine sehr schlechte Idee. Sie werden irgendwann immer mehr Feathers verspotten müssen. Es gibt keine Garantie dafür, dass Ihre Scheine so funktioniert wie Federn, und Sie können falsch negative Ergebnisse erhalten, wie ich es getan habe.

Das Instanziieren einer Feathers-App ist sehr schnell, also verwenden Sie Feathers anstelle von Mocks. So sieht der cli+-Test aus.

Ich habe einen Artikel geschrieben, der sich darauf bezieht. https://medium.com/feathers-plus/automatic-tests-with-feathers-plus-cli-4844721a29cf

danke eddyy, das habe ich gesehen, toller Artikel, hat wirklich geholfen.

Ich hatte Schwierigkeiten, die App zu meinem Kontextobjekt hinzuzufügen, aber ich denke, es wurde schließlich herausgearbeitet!

    const app = feathers();

    contextBefore = {
      type: 'before',
      params: { provider: 'socketio', user: { _id: 1 } },
      data: {
        _id: 1,
      },
      app,
    };

Dann musste ich den Test so ändern, dass er asynchron verwendet wurde.

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,
    });
  });

Ist das der richtige Weg oder gibt es einen besseren Weg?

Sieht gut aus

@fortunes-technology Sie haben Recht. Ich habe mein Code-Snippet aktualisiert. Das sollte funktionieren:

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;
    }
  }
});

kann auch die Abfrage $limit : null verwenden, um sie zu umgehen

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

arve0 picture arve0  ·  4Kommentare

Vincz picture Vincz  ·  4Kommentare

rrubio picture rrubio  ·  4Kommentare

RickEyre picture RickEyre  ·  4Kommentare

codeus-de picture codeus-de  ·  4Kommentare