Code Monkey home page Code Monkey logo

feathers-rethinkdb's Introduction

feathers-rethinkdb

Unmaintained: This project is no longer maintained

Greenkeeper badge

Build Status Dependency Status Download Status

feathers-rethinkdb is a database adapter for RethinkDB, a real-time database.

$ npm install --save rethinkdbdash feathers-rethinkdb

Important: feathers-rethinkdb implements the Feathers Common database adapter API and querying syntax.

This adapter requires a running RethinkDB server.

API

service(options)

Returns a new service instance initialized with the given options. For more information on initializing the driver see the RethinkDBdash documentation.

const r = require('rethinkdbdash')({
  db: 'feathers'
});
const service = require('feathers-rethinkdb');

app.use('/messages', service({
  Model: r,
  db: 'someotherdb', //must be on the same connection as rethinkdbdash
  name: 'messages',
  // Enable pagination
  paginate: {
    default: 2,
    max: 4
  }
}));

Note: By default, watch is set to true which means this adapter monitors the database for changes and automatically sends real-time events. This means that, unlike other databases and services, you will also get events if the database is changed directly.

Options:

  • Model (required) - The rethinkdbdash instance, already initialized with a configuration object. see options here
  • name (required) - The name of the table
  • watch (optional, default: true) - Listen to table changefeeds and send according real-time events on the adapter.
  • db (optional, default: none) - Specify and alternate rethink database for the service to use. Must be on the same server/connection used by rethinkdbdash. It will be auto created if you call init() on the service and it does not yet exist.
  • id (optional, default: 'id') - The name of the id field property. Needs to be set as the primary key when creating the table.
  • events (optional) - A list of custom service events sent by this service
  • paginate (optional) - A pagination object containing a default and max page size

adapter.init([options])

Create the database and table if it does not exists. options can be the RethinkDB tableCreate options.

// Initialize the `messages` table with `messageId` as the primary key
app.service('messages').init({
  primaryKey: 'messageId'
}).then(() => {
  // Use service here
});

adapter.createQuery(query)

Returns a RethinkDB query with the common filter criteria (without pagination) applied.

params.rethinkdb

When making a service method call, params can contain an rethinkdb property which allows to pass additional RethinkDB options. See customizing the query for an example.

Example

To run the complete RethinkDB example we need to install

$ npm install @feathersjs/feathers @feathersjs/errors @feathersjs/express @feathersjs/socketio feathers-rethinkdb rethinkdbdash

We also need access to a RethinkDB server. You can install a local server on your local development machine by downloading one of the packages from the RethinkDB website. It might also be helpful to review their docs on starting a RethinkDB server.

Then add the following into app.js:

const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const socketio = require('@feathersjs/socketio');

const rethink = require('rethinkdbdash');
const service = require('feathers-rethinkdb');

// Connect to a local RethinkDB server.
const r = rethink({
  db: 'feathers'
});

// Create an Express compatible Feathers applicaiton instance.
const app = express(feathers());

// Turn on JSON parser for REST services
app.use(express.json());
// Turn on URL-encoded parser for REST services
app.use(express.urlencoded({extended: true}));
// Enable the REST provider for services.
app.configure(express.rest());
// Enable the socketio provider for services.
app.configure(socketio());
// Register the service
app.use('messages', service({
  Model: r,
  name: 'messages',
  paginate: {
    default: 10,
    max: 50
  }
}));
app.use(express.errorHandler());

// Initialize database and messages table if it does not exists yet
app.service('messages').init().then(() => {
  // Create a message on the server
  app.service('messages').create({
    text: 'Message created on server'
  }).then(message => console.log('Created message', message));

  const port = 3030;
  app.listen(port, function() {
    console.log(`Feathers server listening on port ${port}`);
  });
});

Run the example with node app and go to localhost:3030/messages.

Querying

In addition to the common querying mechanism, this adapter also supports:

$search

Return all matches for a property using the RethinkDB match syntax.

// Find all messages starting with Hello
app.service('messages').find({
  query: {
    text: {
      $search: '^Hello'
    }
  }
});

// Find all messages ending with !
app.service('messages').find({
  query: {
    text: {
      $search: '!$'
    }
  }
});
GET /messages?text[$search]=^Hello
GET /messages?text[$search]=!$

$contains

Matches if the property is an array that contains the given entry.

// Find all messages tagged with `nodejs`
app.service('messages').find({
  query: {
    tags: {
      $contains: 'nodejs'
    }
  }
});
GET /messages?tags[$contains]=nodejs

Nested Queries

Matches if the document contains a nested property that fits the query

Given the following document structure

app.service('people').create([{
    name: 'Dave',
    postalAddress: {
      city: 'Melbourne',
      country: 'US',
      state: 'FL',
      street: '123 6th St',
      zipcode: '32904'
    }
  }, {
    name: 'Tom',
    postalAddress: {
      city: 'Chevy Chase',
      country: 'US',
      state: 'MD',
      street: '71 Pilgrim Avenue',
      zipcode: '20815'
    }
  }, {
    name: 'Eric',
    postalAddress: {
      city: 'Honolulu',
      country: 'US',
      state: 'HI',
      street: '4 Goldfield St',
      zipcode: '96815'
    }
  }])
// Find all people with postalAddress.state that starts with `F`
app.service('people').find({
  query: {
    'postalAddress.state': {
      $search: '^F'
      }
    }
  }
});
GET /people?postalAddress.state[$search]=^F

Customizing the query

In a find call, params.rethinkdb can be passed a RethinkDB query (without pagination) to customize the find results.

Combined with .createQuery(query), which returns a new RethinkDB query with the common filter criteria applied, this can be used to create more complex queries. The best way to customize the query is in a before hook for find. The following example adds a coerceTocondition from RethinkDB coerceTo API to match by any string inside an object.

app.service('mesages').hooks({
  before: {
    find(context) {
      const query = context.service.createQuery(context.params.query);
      
      const searchString = "my search string";
      
      hook.params.rethinkdb = query.filter(function(doc) {
        return doc.coerceTo('string').match('(?i)' + searchString);
      })
    }
  }
});

If you need even more control then you can use service.table (context.service.table in a hook) directly. This way you can create a query from scratch without the the common filter criteria applied. The following example adds a getNearest condition for RethinkDB geospatial queries.

app.service('mesages').hooks({
  before: {
    find(context) {
      const r = this.options.r;

      const point = r.point(-122.422876, 37.777128);  // San Francisco

      // Replace the query with a custom query
      context.params.rethinkdb = context.service.table.getNearest(point, { index: 'location' });
    }
  }
});

Changefeeds

.createQuery(query) can also be used to listen to changefeeds and then send custom events.

Since the service already sends real-time events for all changes the recommended way to listen to changes is with feathers-reactive however.

License

Copyright (c) 2017

Licensed under the MIT license.

feathers-rethinkdb's People

Contributors

codermapuche avatar corymsmith avatar daffl avatar ekryski avatar genyded avatar greenkeeper[bot] avatar greenkeeperio-bot avatar jontey avatar jpeffer avatar jziebikiewicz avatar kc-dot-io avatar marshallswain avatar patrykwegrzyn avatar pkese avatar tarraso avatar tjramage avatar zuck avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

feathers-rethinkdb's Issues

Multiple databases

Hi, is there a way how to use single service Feathers with multiple dynamically created RethinkDB databases? DB should be selected on param (eg. app1.feathersjs.com would use DB app1, app2.feathersjs.com would use DB app2 etc.).

There would be many of those databases so running separate apps is not an option. I know that I could opt not to use this repo, but that means I have to rewrite pretty much everything. Simple DB switching based on before hook should be enough IMO.

Thanks

Error while trying to patch multiple records

Steps to reproduce

Trying to patch using following code (hook it's variable from), according to https://legacy.docs.feathersjs.com/services/readme documentation:

const params = {
      query: {
              page_id: hook.result.id
          }
      }
      hook.app.service('/files').patch(null, { deleted: true }, params)
      .then(() => resolve(hook))
      .catch((err) => {
        hook.app.get('sentryClient').captureException(err);
        reject({});
      });

Expected behavior

set deleted: true to all records in database where page_id is equal hook.result.id

Actual behavior

Error:

{ ReqlRuntimeError: Primary keys must be either a number, string, bool, pseudotype or array (got type NULL):
null in:
r.db("database").table("layouts").get(null).update({
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    deleted: true
    ^^^^^^^^^^^^^
}, {
^^^^
    returnChanges: true
    ^^^^^^^^^^^^^^^^^^^
})
^^

    at Connection._processResponse (/home/vmois/projects/test/node_modules/rethinkdbdash/lib/connection.js:395:15)
    at Socket.<anonymous> (/home/vmois/projects/test/node_modules/rethinkdbdash/lib/connection.js:201:14)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:191:7)
    at readableAddChunk (_stream_readable.js:178:18)
    at Socket.Readable.push (_stream_readable.js:136:10)
    at TCP.onread (net.js:561:20)
From previous event:
    at Function.Term.run (/home/vmois/projects/test/node_modules/rethinkdbdash/lib/term.js:142:15)
    at /home/vmois/projects/test/node_modules/feathers-rethinkdb/lib/index.js:280:44
    at process._tickCallback (internal/process/next_tick.js:109:7)
  msg: 'Primary keys must be either a number, string, bool, pseudotype or array (got type NULL):\nnull',
  message: 'Primary keys must be either a number, string, bool, pseudotype or array (got type NULL):\nnull in:\nr.db("database").table("layouts").get(null).update({\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n    deleted: true\n    ^^^^^^^^^^^^^\n}, {\n^^^^\n    returnChanges: true\n    ^^^^^^^^^^^^^^^^^^^\n})\n^^\n',
  frames: [] }
{}

It's a bug or my fail? Thank you.

Module versions (especially the part that's not working): feathers 2.1.7, feathers-rethinkdb 0.4.3, rethinkdbdash 2.3.29

NodeJS version: 7.10.1

Operating System: Debian 8

Query $In Generating error when passed with more than 30 Values

Steps to reproduce

Create a query for the service using the IN selector that contains 30 or more values

Expected behavior

return records corresponding to past values

Actual behavior

The Rest Service returns an error when many values are passed into the IN

  getAllBens() {
    const collectionStringIDS: Array<string> = this._rest.getApp().get('usuario')['bens'];     
//RETURNS SOMETHING LIKE 
[
"570cacb9-7bca-4ae1-84f7-ec11972536f1",
"0435e776-b665-446c-9d3e-00e62675e10b",
"44e92385-f11d-47b6-9c93-07240f19a2ba"...]

return this._rest.getService('bem')
      .find({
        query: {
          id: { $in: collectionStringIDS }
        }
      });
  }

RESPONSE
{"name":"GeneralError","message":"Cannot convert OBJECT to SEQUENCE in:\nr.db(\"otiseg_db\").table(\"bem\").filter(function(var_62) {\n return r.expr({}).and(r.expr({\n ^^^^^^^^\n 0: \"28807a80-72a7-46d6-aefc-3000cf584668\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 1: \"20a72d99-b9ce-48e5-9333-878f0064bf2a\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 2: \"4ededfb6-56c7-4b16-941b-83643efc66d7\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 3: \"73427e3e-b661-4978-a452-660577723177\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 4: \"855ef7d9-92ae-48cc-8ee2-cc742de9c45c\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 5: \"6a1adc0f-03a5-4518-839f-97bc9a882dea\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 6: \"c0da3143-52ff-4805-b593-424afbd2ec07\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 7: \"a6cec7f9-592c-4525-ac8f-30b646b1b9f4\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 8: \"428f4cb9-0b2e-4fe9-9cb5-2acb718d6eb0\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 9: \"ef0cd3e9-fc0f-410b-b19d-28683da06e0f\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 10: \"699d9882-67c8-4e27-9587-1227c196397d\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 11: \"8ccb8e7a-67be-4742-a52a-876957d72eb4\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 12: \"5616f167-af66-4312-a9f9-20290ca5573d\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 13: \"570cacb9-7bca-4ae1-84f7-ec11972536f1\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 14: \"fdc5cd16-7a2f-40aa-a34d-73989b336c48\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 15: \"3f7a7e0c-3e6f-4215-905e-240a64ae94ef\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 16: \"44e92385-f11d-47b6-9c93-07240f19a2ba\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 17: \"28374bf9-dc9c-4956-9083-e7478e330502\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 18: \"0435e776-b665-446c-9d3e-00e62675e10b\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 19: \"5d9cf7b0-7642-4773-8745-d06f48281d99\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 20: \"2c5bdba0-bcc6-40cb-8ae2-9534efbafb06\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 21: \"0846ecfc-7676-4364-bab1-d412a7ec9983\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 22: \"0846ecfc-7676-4364-bab1-d412a7ec9983\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 23: \"0846ecfc-7676-4364-bab1-d412a7ec9983\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 24: \"2c5bdba0-bcc6-40cb-8ae2-9534efbafb06\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 25: \"2c5bdba0-bcc6-40cb-8ae2-9534efbafb06\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 26: \"2c5bdba0-bcc6-40cb-8ae2-9534efbafb06\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 27: \"2c5bdba0-bcc6-40cb-8ae2-9534efbafb06\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 28: \"2c5bdba0-bcc6-40cb-8ae2-9534efbafb06\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 29: \"28374bf9-dc9c-4956-9083-e7478e330502\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 30: \"2c5bdba0-bcc6-40cb-8ae2-9534efbafb06\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 31: \"28374bf9-dc9c-4956-9083-e7478e330502\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 32: \"14efe2e4-e0a3-4364-9086-1c9024af6a65\",\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 33: \"56396dbc-eb4f-44fe-b016-ba180d652860\"\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n }).contains(var_62(\"id\")))\n ^^^^^^^^^^^^^^^^^^^^^^^^^ \n}).limit(10)\n","code":500,"className":"general-error","data":{},"errors":{}}

Boolean values

Hey,

I was trying to filter TODO list by proving a boolean value (/serviceEndPoint?completed=true), but that didn't work because the value was actually 'true', which results with zero records.

This worked for me:

      if (hook.params.query.completed === 'true') {
        hook.params.query.completed = true;
      } else if (hook.params.query.completed === 'false') {
        hook.params.query.completed = false;
      }

Am I doing something wrong?

Expected type TABLE but found SELECTION

I am getting an error like the following while trying to createQuery as in the documentation.
everything is default and there is a demo service I just created for the experiment.
What could be the problem?

module.exports = {
  before: {
    find(hook) {
      const query = this.createQuery(hook.params.query);
      const r = this.options.r;
      const point = r.point(-122.422876, 37.777128);  // San Francisco
      // Update the query with an additional `getNearest` condition
      hook.params.rethinkdb = query.getNearest(point, { index: 'location' });
    }
  }
}
info: error: demo - Method: find: Expected type TABLE but found SELECTION:
SELECTION ON table(demo) in:
r.db("demo_rethink_db").table("demo").filter(function(var_4) {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    return {}
    ^^^^^^^^^
}).getNearest(r.point(-122.422876, 37.777128), {
^^                                             ^
    index: "location"
    ^^^^^^^^^^^^^^^^^
}).count()
^

error:  ReqlRuntimeError: Expected type TABLE but found SELECTION:
SELECTION ON table(demo)
    at Connection._processResponse (~/demo_rethinkDB/node_modules/rethinkdbdash/lib/connection.js:395:15)
    at Socket.<anonymous> (~/demo_rethinkDB/node_modules/rethinkdbdash/lib/connection.js:201:14)
    at emitOne (events.js:115:13)
    at Socket.emit (events.js:210:7)
    at addChunk (_stream_readable.js:252:12)
    at readableAddChunk (_stream_readable.js:239:11)
    at Socket.Readable.push (_stream_readable.js:197:10)
    at TCP.onread (net.js:589:20)

Geospatial Queries?

Is there a recommended way to use this with Rethink's geospatial queries? I'm having a hard time visualizing how you would do it, except for maybe extending the service class and overriding methods with custom querying?

The ReQL functions like distance and getNearest would be great candidates to have official support.

With distance, you need to be able to pass in the a reference location, either from the client or referencing another database value.

Another complication is that some of these queries require indexing, which is being addressed in another issue.

Official docs on rethinkdb.com

Support searching against nested fields using dot notation

New to feathers and rethink, but from what I have been told, feathersjs does not inherently support searching nested object properties. Often document structures will have nested structures and not being able to search for those properties is quite limiting.

Consider the following structure:

{
"name":"Metro West",
"postalAddress":{
"street":"221 Fielding ST",
"city":"Fairfax",
"state":"VA",
"zipcode":"22036",
"country":"US"
}
}

Searching for all establishments within a given city, state, zip, or country is necessary. By interpreting dot notation of postalAddress.state, web-services could easily pass search parameters in the request and have feathers-rethinkdb properly format the query to search against nested properties.

http://localhost:3030/establishments?postalAddress.state=VA

Expected behavior

Using the aforementioned dot notation for indicated nested properties, feathers-rethinkdb properly formats the search to query nested document properties. In this example, all establishments in the state of VA would be returned.

Actual behavior

No results are found

An in-range update of feathers-hooks is breaking the build 🚨

Version 2.0.2 of feathers-hooks just got published.

Branch Build failing 🚨
Dependency feathers-hooks
Current Version 2.0.1
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As feathers-hooks is “only” a devDependency of this project it might not break production or downstream projects, but “only” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this 💪

Status Details
  • continuous-integration/travis-ci/push The Travis CI build could not complete due to an error Details

Commits

The new version differs by 8 commits.

  • 317b8dc 2.0.2
  • 8faa02a Merge pull request #163 from j2L4e/patch-1
  • be81c5e Update index.d.ts
  • ac5fca6 Merge pull request #162 from Creiger/patch-1
  • 7df95e3 Define return type for hooks
  • f8b5c1d Merge pull request #161 from tycho01/patch-1
  • 6b97ed0 HookProps.type: add 'error'
  • d9983a8 Updating changelog

See the full diff

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

TypeError: Cannot read property '0' of undefined

I have setup a table with custom id field as follows:

  app.use('session', new Service({
    Model: r,
    db,
    id: 'hash',
    name: 'sessions',
  }));

Then I create new entries with preset hash (id) field:
app.service('session').create({hash:'123456', ...})

And I get the above error.

I have managed to replace the following code in function create(data):

      return this.table.insert(data).run().then(function (res) {
        return Object.assign({
          id: data.id ? data.id : res.generated_keys[0]
        }, data);
      });

with

      const idField = this.id;
      return this.table.insert(data).run().then(function (res) {
        const result = Object.assign({}, data);
        if (!data[idField]) result[idField] = res.generated_keys[0];
        return result;
      });

... and things appear to work.

However there are similar problems in patch and update.

Cannot read property '0' of undefined when creating multiple entries

Here's the thing - I need to create entries with custom ids (= not auto-generated ones).

hook.data.id = 'abc'; //Works fine

But when you try to use multiple entries:

hook.data.id = 'abc';
hook.data = [hook.data]; // Produces error

Here is error:

Error: Cannot read property '0' of undefined
    at \feathers-rethinkdb\lib\index.js:239:47
    at tryCatcher (\bluebird\js\release\util.js:16:23)
    at Promise._settlePromiseFromHandler (\bluebird\js\release\promise.js:504:31)
    at Promise._settlePromise (\bluebird\js\release\promise.js:561:18)
    at Promise._settlePromise0 (\bluebird\js\release\promise.js:606:10)
    at Promise._settlePromises (\bluebird\js\release\promise.js:685:18)
    at Async._drainQueue (\bluebird\js\release\async.js:138:16)
    at Async._drainQueues (\bluebird\js\release\async.js:148:10)
    at Immediate.Async.drainQueues (\bluebird\js\release\async.js:17:14)
    at runCallback (timers.js:566:20)
    at tryOnImmediate (timers.js:546:5)
    at processImmediate [as _immediateCallback] (timers.js:525:5)

What can be done to prevent this error?

Support cursors

Resolve the promises with cursors instead of arrays. Then they could be handled with hooks.

Use this config to get the default rethinkdb driver options.

var r = require('rethinkdbdash')({
  pool: false,
  cursor: true
});

Add utility for creating a table

Based on this code: https://github.com/feathersjs/feathers-generator/pull/30/files#r88298599

I think we should move this into a standalone utility inside the feathers-rethinkdb repo, so you can just do something like this.

const createTable = require('feathers-rethinkdb/create-table');
const r = require('rethinkdbdash');

createTable('tableName', r).then(...)

This hides the really ugly table setup code that rethinkdb requires (+1 for hiding it behind a module), but handy for portability (between dbs) and cheap to keep in the app initialization.

Can't figure out how to get $in to work

I've tried various ways to get $in to work from a RESTful URL call, the closest of which I think is :
/api/field[$in]=[‘value1’,’value2’]

but regardless I get the error:

{
  "name": "GeneralError",
  "message": "Cannot convert STRING to SEQUENCE in:\nr.table(\"cz_start\").filter({}).filter(function(var_16) {\n    return r.expr(\"['Testerd','Tester123']\").contains(var_16(\"testCell\"))\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n}).count()\n",
  "code": 500,
  "className": "general-error",
  "data": {},
  "errors": {}
}

Note the quoting ' of the array within the expr() .. I think that's the issue but no idea how to fix it via making a better URL ?

Mention id option in documentation

I think it's worth mention that the default idField is id, as the feathers-authentication module is using _id and seems _id is a convention through

How to use Customizing the query

my code like

app.service('mesages').hooks({
  before: {
    find(context) {
      const query = this.createQuery(context.params.query);
      
      const searchString = "my search string";
      
      hook.params.rethinkdb = query.filter(function(doc) {
        return doc.coerceTo('string').match('(?i)' + searchString);
      })
    }
  }
});

but it gives me an error this.createQuery is not a function

Querying for numeric equality

Steps to reproduce

Querying for numeric equality isn't working. I have a "cashflow" service with one record as follows:

{
    "total": 1,
    "data": [
        {
            "expenses": [],
            "id": "f73e65a6-3364-4dad-855f-fc921f4dc532",
            "income": [],
            "spending": [],
            "year": 2017
        }
    ],
    "limit": 10,
    "skip": 0
}

but when I try and query by year as so:

localhost:3030/cashflow?year=2017

I receive no results. I've tried the $search method as well, like so:

localhost:3030/cashflow?year[$search]=2017

but receive errors around strings being expected but finding numbers instead:

{
    "name": "GeneralError",
    "message": "Expected type STRING but found NUMBER in:\nr.db(\"feathers_nuxt\").table(\"cashflow\").filter(function(var_35) {\n    return r.expr({}).and(var_35(\"year\").match(\"2017\"))\n                          ^^^^^^^^^^^^^^               \n}).limit(10)\n",
    "code": 500,
    "className": "general-error",
    "data": {},
    "errors": {}
}

which confirms my data is definitely in the correct type, ie numeric.

Expected behavior

My 2017 record should be returned.

Actual behavior

No records returned.

System configuration

feathers-rethinkdb v0.5.0
node v8.9.3
Windows 10
Webpack

Optimized queries using indexes.

Current queries do not use an index. With RethinkDB, you must manually specify an index in order to achieve higher performance. Queries need to automatically use an index when it's an option. We could also make an option for the user to specify an index with $index.

Service hooks called multiple times

We have a user service as follows:

module.exports = function(){
  const app = this;

  const r = require('rethinkdbdash')({
    db: 'application'
  });

  const options = {
    Model: r,
    paginate: {
      default: 5,
      max: 25
    },
    name: 'user',
    id: 'email'
  };

  // Initialize our service with any options it requires
  app.use('/user', service(options));

  // Get our initialize service to that we can bind hooks
  const userService = app.service('/user');

  // Set up our before hooks
  userService.before(hooks.before);

  // Set up our after hooks
  userService.after(hooks.after);

  //Only return events for ourselves
  userService.filter(function(data, connection) {
    if (!data.email || !_.get(connection, 'user.email', false) !== data.email) {
      return false;
    }

    return data
  });

};

There are then hooks defined for the user service

exports.before = {
  all: [
    function (hook) {
      console.log(hook.method + ' User before')
    },
  ],
  find: [
  ],
  get: [
  ],
  create: [
  ],
  update: [

  ],
  patch: [
  ],
  remove: [
  ]
};

exports.after = {
  all: [
    function (hook) {
      console.log(hook.method + ' User after')
    },
    hooks.remove('password')
  ],
  find: [],
  get: [],
  create: [
  ],
  update: [
  ],
  patch: [
  ],
  remove: []
};

Then simply POST a new user to localhost:3000/user and the console output is:

create User before
create User after
create User after

We then replaced the rethinkdb strategy with memory and the output is:

create User before
create User after


    "feathers": "^2.1.1",
    "feathers-authentication": "^1.2.0",
    "feathers-authentication-client": "^0.3.1",
    "feathers-authentication-hooks": "^0.1.1",
    "feathers-authentication-jwt": "^0.3.1",
    "feathers-authentication-local": "^0.3.4",
    "feathers-authentication-oauth1": "^0.2.3",
    "feathers-authentication-oauth2": "^0.2.4",
    "feathers-configuration": "^0.3.3",
    "feathers-errors": "^2.6.2",
    "feathers-hooks": "^1.8.1",
    "feathers-hooks-common": "^2.0.3",
    "feathers-permissions": "^0.1.1",
    "feathers-rest": "^1.7.1",
    "feathers-rethinkdb": "^0.4.1",
    "feathers-socketio": "^1.5.2",

Set default value in patch/update for "params" parameter

Steps to reproduce

Call directly from server (i.e. not triggered by client):

super.patch('H1osMjJRx', { name: 'A new name' }); //  <--- notice, no "params" parameter

Expected behavior

Object with ID H1osMjJRx has it's name prop updated to "A new name".

Actual behavior

feathers-rethinkdb complains: "Cannot read property 'rethinkdb' of undefined"

This happens because the optional "params" parameter is not passed. Because the update/patch methods unsafely call the rethinkdb property directly on params (without first checking for null/undefined), it throws an error. This is okay when calling from the client as params can be easily passed through to the super method but, when called on the server, it won't necessarily be there.

See line 190: https://github.com/feathersjs/feathers-rethinkdb/blob/27f27d3f079c8833a7f7baa9776fb9c8e01284f6/src/index.js#L190

In the above, the params parameter should have a default value (params = {}), like the find method.

Change feeds hang silently after disconnecting from server or after re-balancing a sharded cluster

Hi

By default feathers-rethinkdb watches the service table for changes and transforms these changes to hooks. However when the connection to the database is disconnected or if you try to rebalance or reconfigure a sharded cluster (which causes some downtime in rethinkdb) you no longer get change feeds.

The problem is found in line 305

this._cursor = this.table.changes().run().then(function (cursor) {
  cursor.each((error, data) => {
        if (error || typeof this.emit !== 'function') {
          return;
        }

Here the cursor returns an error with error.name = ReqlOpFailedError and in order to get the change feed again you have to re run the this.table.changes() function again and reinitialize the cursor.

I am using master branch running on Ubuntu 16.04 and nodejs v7.10.0

Where is ../lib??

This example has the line:

const service = require('../lib');

...where is this?

TypeError: Cannot read property '0' of undefined

I have setup a table with custom id field as follows:

  app.use('session', new Service({
    Model: r,
    db,
    id: 'hash',
    name: 'sessions',
  }));

Then I create new entries with preset hash (id) field:
app.service('session').create({hash:'123456', ...})

And I get the above error.

I have managed to replace the following code in function create(data):

      return this.table.insert(data).run().then(function (res) {
        return Object.assign({
          id: data.id ? data.id : res.generated_keys[0]
        }, data);
      });

with

      const idField = this.id;
      return this.table.insert(data).run().then(function (res) {
        const result = Object.assign({}, data);
        if (!data[idField]) result[idField] = res.generated_keys[0];
        return result;
      });

... and things appear to work.

However there are similar problems in patch and update.

event filters duplicated

I have a filter registered on the 'created' event. It is getting triggered for each socketio connection I have connected. Is this expected behavior? Is there a way to only get one event notification? I dont understand why I would get a separate filter trigger for each one. Additionally, connection only tells me the client connection is socketio. Not very helpful in identifying each.

The default todos created event is too broad so I I'm trying to capture the event and emit a more specific event. My usecase is logs from a bunch of different kiosks. So I want an admin to be able to register to see only events for a single kiosk. Like so:

const logServiceFeathers = app.service('logs');
logServiceFeathers.filter('created', function(data, connection, hook) {
  var event = 'logs';
  if(data && data.unitId){
    event += ' ' + data.unitId;
  } else {
    //ignore
    return;
  }
  //emits logs for each unit separately
  app.io.emit(event, JSON.stringify(data));
  return false;
});

Am I doing this wrong?

Hangs creating pool on Windows

Steps to reproduce

I am on Windows 10 and trying the example app. Rethink is running on the default port and the DB and table got created but when I run the app, it hangs at 'Creating a pool connected to localhost:28015'. Any thoughts on what to try or check?

image

Challenges with watching changefeeds and hooks

#75 introduced somewhat of a fix for the following problem:

When watching RethinkDB changefeeds we were just sending the data we get from the database directly as a real-time event. Unlike a normal method call, this means that the data did not get processed through hooks (specifically after) hooks. The current solution is to run the data manually through the respective methods after hooks.

Potential problems are that there is no way to get the information what original method call caused the change (or if it was a Feathers method call at all). This means that hook.params will be empty (no params.user, params.provider, params.query etc.).

Currently hook.params will be set to { query: {} }

I don't think this is really a fixable issue but will put it here for visibility and probably add that caveat to the docs.

Is this still in dev?

Wondering if this will be continue to be worked on, simply given the fact rethinkdb, is already realtime.

Put additional info to after hooks called by rethinkdb changefeed

It could be useful to have:

  1. old_value, when after hook called by changefeed and hook.method is patch or update
  2. some indicator field which tells you that hook called by rethinkdb changefeed. E.g. hook.params.changefeed = true or something similar. I think it's not enough convenient to rely always on hook.params.provider and hook.params.user.

I would like to create a PR for it if nobody have some args against such changes.

Create tests for returning cursors.

I've created a returnCursors option that will return a RethinkDB cursor from find queries. It's not tested, and it would also be good to see if this can be used in any of the other methods.

$sort doesn't seem to work as expected

There seems to be some issues with the $sort param.

It works correctly when I sort by the id of a table, but if I sort via other fields, I get inconsistent or broken results.

The fields I am trying to sort by have an index in Rethink, and sorting in Rethink directly works without any issues.

Any one else run into issues like this?

$search not working - cannot convert `undefined` with r.expr()

Hi, when I'm trying to use $search in this way:

const query = {
   name: {
      $search: 'something',
   },
};

I get console error:

Error: Cannot convert `undefined` with r.expr() in:
r.table("users").filter({}).orderBy(r.desc("createdDate")).and(undefined).limit(20)

Am I doing something wrong? How to use $search?

FeathersJS REST Multiple Query String

  • [ hello , how filter like ?messages?catygories[$in]=6515452f-c68b-40d1-bdaa-a37effef8533 , i found information about qs npm package , but not understand how use it, i console i have ]

`Method: find: Cannot convert STRING to SEQUENCE in:
r.db("news").table("messages").filter(function(var_4) {
return r.expr({}).and(r.expr("6515452f-c68b-40d1-bdaa-a37effef8533").contains(var_4("catygories")))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}).limit(10)

error: ReqlRuntimeError: Cannot convert STRING to SEQUENCE
`

please show example, thank you so mutch kind peoples ! :)

Add $regexp type filter

Adding this case to /src/parse.js can filter fields by regexp:
case '$regexp': isFilter = true; reQuery = reQuery.filter(function(doc){ return doc(qField).match(qValue.$regexp) }); break;

Query with $and condition?

Hi, let's assume my sample users data looks like:

[{
  firstName: 'John',
  secondName: 'Smith',
  hobbies: ['fishing', 'cooking', 'skiing']
},
...
]

I would like to find all users with 'John' in firstName OR in lastName AND 'fishing' OR 'skiing' in hobbies. I need it for searching and filtering in app.

Is there any way to accomplish that? Any kind of $and? My current query (below) works, but is terrible and weird. And if I add another hobby filter (ex. 'cooking'), it would be much longer.

const query = {
  $or: [
    {
      firstName: {
        $search: '(?i)John',
        hobbies: { $contains: 'fishing' },
      },
      lastName: {
        $search: '(?i)John',
        hobbies: { $contains: 'fishing' },
      },
      firstName: {
        $search: '(?i)John',
        hobbies: { $contains: 'skiing' },
      },
      lastName: {
        $search: '(?i)John',
        hobbies: { $contains: 'skiing' },
      },
    },
  ],
};

Doesn't create database or tables

Steps to reproduce

Try to use it without creating the database/table first

Expected behavior

Should create the database and table

Actual behavior

Throws an error which can't even be deciphered without debugging node

Database feathers does not exist.

Table feathers.users does not exist.

System configuration

Module versions (especially the part that's not working):

"feathers-rethinkdb": "^0.3.3"

NodeJS version:

7.3.0

Operating System:

Windows 10

Incorrect error message and/or lack of support for DB toggling/changing

Steps to reproduce

  1. Configure a service without the db: option in the rethink options and you will get the error

You must provide either an instance of r that is preconfigured with a db, or a provide options.db.

However if you specify the options.db in the service config as the error above states, it still does not work:

app.use('messages', service({
      Model: r,
      db: 'test',
      name: 'messages',
      paginate: {
        default: 25,
        max: 250
      }
    }))

You still get the same error. If you specify the db in the rethink conifg, it works but that does not provide any way to change to DB 'on the fly'.

Expected behavior

Should be able to change the DB somehow. You can run with 2 (or more) rethink pools (we think) on models with different names, but that seems like wasted resource and redundant code. Or at a minimum, the error above should be changed so others do not spend time trying something that will not work. The code only ever checks for a db from rethinkdbdash and nothing else ...

// Make sure the user connected a database before creating the service.
    if (!options.r._poolMaster._options.db) {
      throw new Error('You must provide either an instance of r that is preconfigured with a db, or a provide options.db.');
    }
...
let db = this.options.r._poolMaster._options.db;
...

Actual behavior

You can only really use ONE rethink DB, which is not practical in many real applications with distributed data (or our use case where some data comes from a common DB, but other data comes from a DB specific to the users org). We could use multiple models with different names (we think), but that allocates pools for each one which seems like resource overkill and results in duplicate code to a large degree. You can also currently specify the db in the .run() for rethink without specifying it in the config first (outside of the Feathers service) e.g.:

return r.db('test').tableList().contains('messages')
      .do(tableExists => r.branch( tableExists, {created: 0},
          r.tableCreate('messages'))).run();

... and that works fine but in the Feathers rethink based services the run is not exposed directly. So, there doesn't seem to be any practical way to change or specify the DB for service calls. We also looked into the populate hook and while it can meet the same need the same way (multiple pools) - it does not solve the root issue.

System configuration

Latest Feathers, rethink, rethinkdbdash via npm

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.