Feathers: アソシエーションを取得する方法

作成日 2016年08月08日  ·  30コメント  ·  ソース: feathersjs/feathers

そこで、feathersフレームワークを使用してアプリを開発しました。 別のサービスからのデータにアクセスしたいデータベースサービスに接続されたフックがあります。 これは可能で、簡単ですか? そのサービスがいくつかの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')を介して別のサービスにアクセスし、必要なメソッドを呼び出すことができます。 フックが待機するために、Promise( 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;
    });
  };
};

全てのコメント30件

はい。 関連アイテムを取得する方法hook.app.service('servicename')を介して別のサービスにアクセスし、必要なメソッドを呼び出すことができます。 フックが待機するために、Promise( 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を更新する必要があります。

└── [email protected]

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にはなく、page変数にのみ含まれています。

学んだ教訓 :)

ああ、 @ dafflに助けてくれてありがとう。

クライアント側では機能しません。 ( paginate: false,変数)。

queryのみがクライアントとサーバーの間で渡されます。 クライアントにすべての全体を要求させないようにします(データベースに100万のレコードがある場合、サーバーとクライアントの両方が強制終了されます)。 それを回避する方法がない場合は、サーバー上のフックparams.queryからparamsに特別なクエリパラメーター(例: $paginate )をマップする必要があります。

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

ただし、これによりサーバーが無限ループに陥り、ノードアプリが最終的にクラッシュします。

sequelizeで接続されたDBとしてMySQLを使用しています。

私は何が間違っているのですか?

アップデート

postedByフィールドに基づいてユーザーフィールドにデータを入力するために、投稿に同様のフックを設定しました。 したがって、ユーザーフックがポストフックをトリガーし、それが元のユーザーフックをトリガーし、ループが継続して無限ループとメモリオーバーフローが発生するようです。

浅い関連アイテムのみを設定する方法、つまりフックは、最初のレベルでのみ関連アイテムのみをプルします。

@dafflコードは機能しませんでしたが、あなたのアイデアは素晴らしいです。
それを機能させるには、hook.paginateをhook.params.paginateに変更する必要がありました。
そして、私はあなたがそこにあなたが望むものを何でも送ることができるように少し変更を加えました。
したがって、$ paginate:{value:false}を使用して、ページ付けを無効にするか、
$ paginate:{値:{デフォルト:100、最大: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; } } });

考慮すべきもう1つのことは、ページ付けが無効になっている場合、データは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もfalseになると思います。 多分

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

findOnefindで、 $limitは1です。

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

@dafflマングースにはfindOneがあるので尋ねましたが、何かがすでに見つかっている場合は、残りのすべてのコレクションを検索しないことを提案しました。 そこで、findOneをよりスマートなものとして考え、limit = 1で検索しました...それで私は尋ねました。

私は通常、これをすばやく見つけるために行います:

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

.findOne()メソッドのプラグインを作成しました: feathers-findone

クライアントの$ paginate回避策を追加する方法の例が見つかりませんでした。 そこで、app.hooks.jsファイルからいくつかの変更を加えて実行するbeforeフックを作成しました。

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

このためのユニットまたは統合テストをどのように作成しますか?

だから私が私のフックに次のものを持っているなら

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

私はfeathers-plusジェネレーターから自動生成されたユニットテストを使用しています。
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,
    };

次に、非同期を使用するようにテストを修正する必要がありました。

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

クエリ$ limit:nullを使用してバイパスすることもできます

このページは役に立ちましたか?
0 / 5 - 0 評価