Databases ========= In the :doc:`./services` we created a custom in-memory messages service that can create, update and delete messages. You can probably imagine how we could implement the same thing using a database instead of storing the messages in memory so there isn’t really a database that Feathers doesn’t support. Writing all that code yourself is pretty repetitive and cumbersome though which is why Feathers has a collection of pre-built services for different databases. They offer most the basic functionality and can always be fully customized to your requirements using :doc:`./hooks`. Feathers database adapters support a common :doc:`../../api/databases/common`, pagination and :doc:`../../api/databases/querying` for many popular databases and NodeJS ORMs: +-------------------------------------------+-----------------------------------+ | Database | Adapter | +===========================================+===================================+ | In memory | `feathers-memory `_, | | | `feathers-nedb `_ | +-------------------------------------------+-----------------------------------+ | Localstorage, AsyncStorage | `feathers-localstorage `_ | +-------------------------------------------+-----------------------------------+ | Filesystem | `feathers-nedb `_ | +-------------------------------------------+-----------------------------------+ | MongoDB | `feathers-mongodb `_, | | | `feathers-mongoose `_ | +-------------------------------------------+-----------------------------------+ | MySQL, PostgreSQL, MariaDB, SQLite, MSSQL | `feathers-knex `_, | | | `feathers-sequelize `_, | | | `feathers-objection `_ | +-------------------------------------------+-----------------------------------+ | Elasticsearch | `feathers-elasticsearch `_ | +-------------------------------------------+-----------------------------------+ | RethinkDB | `feathers-rethinkdb `_ | +-------------------------------------------+-----------------------------------+ .. tip:: Each one of the linked adapters has a complete REST API example in their readme. In this chapter we will look at the basic usage of the in-memory database adapter. .. important:: You should be familiar with the database technology and ORM (`Sequelize `_, `KnexJS `_ or `Mongoose `_) before using a Feathers database adapter. An in-memory database --------------------- `feathers-memory `_ is a Feathers database adapter that - similar to our messages service - stores its data in memory. We will use it for the examples because it also works in the browser. Let’s install it with: .. code-block:: sh npm install feathers-memory --save We can use the adapter by requiring it and initializing it with the options we want. Here we enable pagination showing 10 entries by default and a maximum of 25 (so that clients can’t just request all data at once and crash our server): .. code:: js const feathers = require('@feathersjs/feathers'); const memory = require('feathers-memory'); const app = feathers(); app.use('messages', memory({ paginate: { default: 10, max: 25 } })); That’s it. We have a complete CRUD service for our messages with querying functionality. In the browser -------------- We can also include ``feathers-memory`` in the browser, most easily by loading its browser build which will add it as ``feathers.memory``. In ``public/index.html``: .. code:: html Feathers Basics

Welcome to Feathers

Open up the console in your browser.

And ``public/client.js``: .. code:: js const app = feathers(); app.use('messages', feathers.memory({ paginate: { default: 10, max: 25 } })); Querying -------- As mentioned, all database adapters support a common way of querying the data in a ``find`` method call using ``params.query``. You can find a complete list in the :doc:`../../api/databases/querying`. With pagination enabled, the ``find`` method will return an object with the following properties: - ``data`` - The current list of data - ``limit`` - The page size - ``skip`` - The number of entries that were skipped - ``total`` - The total number of entries for this query The following example automatically creates 100 messages and makes some queries. You can add it at the end of both ``app.js`` and ``public/client.js`` to see it in Node and the browser: .. code:: js async function createAndFind() { // Stores a reference to the messages service so we don't have to call it all the time const messages = app.service('messages'); for(let counter = 0; counter < 100; counter++) { await messages.create({ counter, message: `Message number ${counter}` }); } // We show 10 entries by default. By skipping 10 we go to page 2 const page2 = await messages.find({ query: { $skip: 10 } }); console.log('Page number 2', page2); // Show 20 items per page const largePage = await messages.find({ query: { $limit: 20 } }); console.log('20 items', largePage); // Find the first 10 items with counter greater 50 and less than 70 const counterList = await messages.find({ query: { counter: { $gt: 50, $lt: 70 } } }); console.log('Counter greater 50 and less than 70', counterList); // Find all entries with text "Message number 20" const message20 = await messages.find({ query: { message: 'Message number 20' } }); console.log('Entries with text "Message number 20"', message20); } createAndFind(); As a REST API ------------- In the :doc:`./rest` we created a REST API from our custom messages service. Using a database adapter instead will make our ``app.js`` a lot shorter: .. code:: js const feathers = require('@feathersjs/feathers'); const express = require('@feathersjs/express'); const memory = require('feathers-memory'); const app = express(feathers()); // Turn on JSON body parsing for REST services app.use(express.json()) // Turn on URL-encoded body parsing for REST services app.use(express.urlencoded({ extended: true })); // Set up REST transport using Express app.configure(express.rest()); // Initialize the messages service app.use('messages', memory({ paginate: { default: 10, max: 25 } })); // Set up an error handler that gives us nicer errors app.use(express.errorHandler()); // Start the server on port 3030 const server = app.listen(3030); // Use the service to create a new message on the server app.service('messages').create({ text: 'Hello from the server' }); server.on('listening', () => console.log('Feathers REST API started at localhost:3030')); After starting the server with ``node app.js`` we can pass a query e.g.  by going to `localhost:3030/messages?$limit=2 `_. .. note:: The :doc:`../../api/databases/querying` has more examples how URLs should look like. What’s next? ------------ Feathers database adapters are a quick way to get an API up and running. The great thing is that :doc:`./hooks` still give us all the flexibility we need to customize how they work. We already saw how we can easily create a database backed REST API, in the :doc:`real-time` we will make our API real-time.