NeDB: una base de datos JavaScript ligera

    Cuando piensa en una base de datos, lo primero que se le puede ocurrir es MySQL, MongoDB o PostgreSQL. Si bien todas estas son excelentes opciones para almacenar datos, todas est谩n sobrecargadas para la mayor铆a de las aplicaciones.

    Considere una aplicaci贸n de chat de escritorio escrita con el Electr贸n framework en JavaScript. Si bien los datos del chat (mensajes, contactos, historial, etc.) probablemente se originen en un servidor API, tambi茅n deber铆an almacenarse localmente dentro de la aplicaci贸n. Potencialmente, podr铆a tener miles de mensajes, todos los cuales deber铆an almacenarse para facilitar el acceso y la b煤squeda.

    Entonces, 驴Qu茅 haces? Una opci贸n es almacenar todos estos datos en un archivo en alg煤n lugar y simplemente buscarlos cada vez que necesite recuperarlos, pero esto puede ser ineficiente. Otra opci贸n es simplemente no almacenar en cach茅 los datos localmente y hacer una llamada al servidor de API cada vez que necesite m谩s datos, pero entonces su aplicaci贸n responder谩 menos y utilizar谩 muchos m谩s datos de red.

    Una mejor idea es utilizar una base de datos incorporada / ligera, como NeDB. Esto tiene m谩s sentido porque su aplicaci贸n no atender谩 a miles de usuarios ni manejar谩 gigabytes de datos.

    NeDB es muy parecido a SQLite ya que es una versi贸n m谩s peque帽a e integrable de un sistema de base de datos mucho m谩s grande. En lugar de ser un almac茅n de datos SQL m谩s peque帽o, NeDB es un almac茅n de datos NoSQL m谩s peque帽o que imita MongoDB.

    Una base de datos liviana generalmente almacena sus datos en la memoria o en un archivo de texto sin formato (con 铆ndices para b煤squedas r谩pidas). Esto ayuda a reducir el espacio total de la base de datos en el sistema, que es perfecto para aplicaciones m谩s peque帽as. A modo de comparaci贸n, el archivo tar de MySQL (para Mac OSX) es de 337 MB, mientras que NeDB (sin comprimir, no minificado) tiene solo 1,5 MB.

    Una de las mejores cosas de NeDB espec铆ficamente es que su API es un subconjunto de la API de MongoDB, por lo que si est谩 familiarizado con MongoDB, no deber铆a tener problemas para trabajar con NeDB despu茅s de la configuraci贸n inicial.

    Nota: A partir de v1.8.0, NeDB a煤n no se ha actualizado a algunos de los nuevos nombres de m茅todos de Mongo, como insertOne, insertMany y la eliminaci贸n de findOne.

    Introducci贸n a NeDB

    Primero, instale el m贸dulo con NPM:

    $ npm install nedb --save
    

    El m贸dulo est谩 escrito en JavaScript puro, por lo que no deber铆a haber ning煤n problema al compilar plugins nativos como ocurre a veces con los controladores MongoDB.

    Si planea usarlo en el navegador, use Bower para instalar:

    $ bower install nedb
    

    Como todos los clientes de bases de datos, el primer paso es conectarse a la base de datos backend. Sin embargo, en este caso no hay una aplicaci贸n externa a la que conectarse, por lo que solo necesitamos indicarle la ubicaci贸n de sus datos. Con NeDB, tiene algunas opciones para guardar sus datos. La primera opci贸n es guardar los datos en la memoria:

    var Datastore = require('nedb');
    var db = new Datastore();
    
    // Start issuing commands right away...
    

    Esto lo iniciar谩 sin datos y, cuando salga de la aplicaci贸n, se perder谩n todos los datos guardados. Aunque es ideal para usar durante pruebas o sesiones m谩s cortas (como en el navegador).

    O la otra opci贸n es guardar los datos en un archivo. La diferencia aqu铆 es que debe especificar la ubicaci贸n del archivo y cargar los datos.

    var Datastore = require('nedb');
    var db = new Datastore({ filename: 'path/to/your/file' });
    
    db.loadDatabase(function(err) {
        // Start issuing commands after callback...
    });
    

    Si no quieres llamar db.loadDatabase para cada base de datos que cargue, siempre puede usar el autoload: true opci贸n tambi茅n.

    Una cosa importante a tener en cuenta es que cada archivo es equivalente a uno colecci贸n en MongoDB. Por lo tanto, si tiene varias colecciones, deber谩 cargar varios archivos al inicio. Entonces, su c贸digo podr铆a verse as铆:

    var Datastore = require('nedb');
    var users = new Datastore({ filename: 'users.db', autoload: true });
    var tweets = new Datastore({ filename: 'tweets.db', autoload: true });
    var messages = new Datastore({ filename: 'messages.db', autoload: true });
    

    Guardar datos

    Despu茅s de cargar sus datos desde archivos (o crear almacenamiento en memoria), querr谩 comenzar a guardar datos.

    Al igual que los controladores Mongo, usar谩 insert para crear un nuevo documento:

    var Datastore = require('nedb');
    var users = new Datastore();
    
    var scott = {
        name: 'Scott',
        twitter: '@ScottWRobinson'
    };
    
    users.insert(scott, function(err, doc) {
        console.log('Inserted', doc.name, 'with ID', doc._id);
    });
    
    // Prints to console...
    // (Note that ID will likely be different each time)
    //
    // "Inserted Scott with ID wt3Nb47axiOpme9u"
    

    Esta inserci贸n se puede ampliar f谩cilmente para guardar varios documentos a la vez. Usando el mismo m茅todo, simplemente pase una matriz de objetos y cada uno se guardar谩 y se le devolver谩 en la devoluci贸n de llamada:

    var Datastore = require('nedb');
    var users = new Datastore();
    
    var people = [];
    
    var scott = {
        name: 'Scott Robinson',
        age: 28,
        twitter: '@ScottWRobinson'
    };
    
    var elon = {
        name: 'Elon Musk',
        age: 44,
        twitter: '@elonmusk'
    };
    
    var jack = {
        name: 'Jack Dorsey',
        age: 39,
        twitter: '@jack'
    };
    
    people.push(scott, elon, jack);
    
    users.insert(people, function(err, docs) {
        docs.forEach(function(d) {
            console.log('Saved user:', d.name);
        });
    });
    
    // Prints to console...
    //
    // Saved user: Scott Robinson
    // Saved user: Elon Musk
    // Saved user: Jack Dorsey
    

    La actualizaci贸n de documentos existentes funciona de manera muy similar, excepto que deber谩 proporcionar una consulta para indicarle al sistema qu茅 documentos deben actualizarse.

    Cargando datos

    Ahora que tenemos un mont贸n de datos guardados, es hora de recuperarlos de la base de datos. Nuevamente, seguiremos la misma convenci贸n que Mongo con el find m茅todo:

    var Datastore = require('nedb');
    var users = new Datastore();
    
    // Save a bunch of user data here...
    
    users.findOne({ twitter: '@ScottWRobinson' }, function(err, doc) {
        console.log('Found user:', doc.name);
    });
    
    // Prints to console...
    //
    // Found user: Scott Robinson
    

    Y nuevamente, podemos usar una operaci贸n similar para recuperar m煤ltiples documentos. Los datos devueltos son solo una matriz de documentos coincidentes:

    var Datastore = require('nedb');
    var users = new Datastore();
    
    // Save a bunch of user data here...
    
    users.find({ age: { $lt: 40 }}, function(err, docs) {
        docs.forEach(function(d) {
            console.log('Found user:', d.name);
        });
    });
    
    // Prints to console...
    //
    // Found user: Jack Dorsey
    // Found user: Scott Robinson
    

    Es posible que haya notado en este 煤ltimo ejemplo de c贸digo que NeDB, como era de esperar, es capaz de realizar consultas m谩s complejas, como comparaciones de n煤meros. Los siguientes operadores est谩n disponibles para buscar / comparar documentos:

    • $lt, $lte: menor que, menor que o igual
    • $gt, $gte: mayor, mayor o igual que
    • $in: valor contenido en la matriz
    • $nin: valor no contenido en la matriz
    • $ne: no es igual
    • $exists: comprueba la existencia (o no existencia) de una propiedad determinada
    • $regex: coincide con la cadena de una propiedad con expresiones regulares

    Tambi茅n puede utilizar las operaciones est谩ndar de clasificaci贸n, limitaci贸n y omisi贸n. Si no se devuelve la llamada al find m茅todo, luego un Cursor En su lugar, se le devolver谩 el objeto, que luego podr谩 usar para ordenar, limitar y omitir. A continuaci贸n, se muestra un ejemplo de ordenaci贸n alfab茅tica por nombre:

    var Datastore = require('nedb');
    var users = new Datastore();
    
    // Save a bunch of user data here...
    
    users.find({}).sort({name: 1}).exec(function(err, docs) {
        docs.forEach(function(d) {
            console.log('Found user:', d.name);
        });
    });
    
    // Prints to console...
    //
    // Found user: Elon Musk
    // Found user: Jack Dorsey
    // Found user: Scott Robinson
    

    Las otras dos operaciones, saltar y limitar, funcionan de manera muy similar a esto.

    Hay bastantes operadores m谩s admitidos por el find y findOne m茅todos, pero no los veremos todos aqu铆. Puede leer en detalle sobre el resto de estas operaciones en el encontrar documentos secci贸n del archivo README.

    Eliminar datos

    No hay mucho que decir sobre la eliminaci贸n de datos aparte de que funciona de manera similar a la find m茅todos. Utilizar谩 los mismos tipos de consultas para encontrar los documentos relevantes en la base de datos. Los que se encuentran se eliminan.

    var Datastore = require('nedb');
    var users = new Datastore();
    
    // Save a bunch of user data here...
    
    users.remove({ name: { $regex: /^Scott/ } }, function(err, numDeleted) {
         console.log('Deleted', numDeleted, 'user(s)');
    });
    
    // Prints to console...
    //
    // Deleted 1 user(s)
    

    Por defecto, el remove El m茅todo solo elimina un documento. Para eliminar varios documentos con una sola llamada, debe configurar el multi opci贸n a true.

    var Datastore = require('nedb');
    var users = new Datastore();
    
    // Save a bunch of user data here...
    
    users.remove({}, { multi: true }, function(err, numDeleted) {
         console.log('Deleted', numDeleted, 'user(s)');
    });
    
    // Prints to console...
    //
    // Deleted 3 user(s)
    

    Datos de indexaci贸n

    Al igual que con cualquier otra base de datos, puede establecer 铆ndices en sus datos para una recuperaci贸n m谩s r谩pida o para hacer cumplir ciertas restricciones, como valores 煤nicos. Para crear el 铆ndice, use el ensureIndex m茅todo.

    Los tres tipos de 铆ndices admitidos actualmente son:

    • unique: aseg煤rese de que el campo dado sea 煤nico en toda la colecci贸n
    • sparse: no indexar documentos en los que el campo dado no est谩 definido
    • expireAfterSeconds: elimina el documento despu茅s del n煤mero de segundos especificado (tiempo para viviro TTL)

    El 铆ndice TTL es especialmente 煤til, en mi opini贸n, ya que le evita tener que escribir c贸digo para escanear y eliminar con frecuencia datos que han caducado.

    Esto puede resultar 煤til, por ejemplo, con solicitudes de restablecimiento de contrase帽a. Si tienes un PasswordReset objeto almacenado en su base de datos, no querr谩 que sea v谩lido para siempre. Para ayudar a proteger al usuario, probablemente deber铆a caducar y eliminarse despu茅s de unos d铆as. Este 铆ndice TTL puede manejar su eliminaci贸n por usted.

    En el siguiente ejemplo, hemos colocado el unique restricci贸n en los identificadores de Twitter de los documentos. Esto significa que si un usuario se guarda con el mismo identificador de Twitter que otro usuario, se lanzar谩 un error.

    var Datastore = require('nedb');
    var users = new Datastore();
    
    users.ensureIndex({ fieldName: 'twitter', unique: true });
    
    var people = [];
    
    var jack = {
        name: 'Jack Dorsey',
        age: 39,
        twitter: '@jack'
    };
    
    var jackSmith = {
        name: 'Jack Smith',
        age: 68,
        twitter: '@jack'
    };
    
    people.push(jack, jackSmith);
    
    users.insert(people, function(err, docs) {
        console.log('Uh oh...', err);
    });
    
    // Prints to console...
    //
    // Uh oh... Can't insert key @jack, it violates the unique constraint
    

    Llev谩ndolo m谩s lejos

    Si bien la API de NeDB es f谩cil de usar y todo, su c贸digo puede volverse bastante dif铆cil de trabajar si no est谩 bien pensado y organizado. Aqu铆 es donde los mapeadores de documentos de objetos (que es como un ORM) ven a jugar.

    Utilizando la ODM de camuflaje (que cre茅), simplemente puede tratar los almacenes de datos NeDB como clases de JavaScript. Esto le permite especificar un esquema, validar datos, extender esquemas y m谩s. Camo incluso tambi茅n funciona con MongoDB, por lo que puede usar NeDB en entornos de prueba / desarrollo y luego usar Mongo para su sistema de producci贸n sin tener que cambiar nada de su c贸digo.

    Aqu铆 hay un ejemplo r谩pido de c贸mo conectarse a la base de datos, declarar un objeto de clase y guardar algunos datos:

    var connect = require('camo').connect;
    var Document = require('camo').Document;
    
    class User extends Document {
        constructor() {
            super();
    
            this.name = String;
            this.age = Number;
            this.twitter = Sring;
        }
    
        get firstName() {
            return this.name.split(' ')[0];
        }
    }
    
    var scott = User.create({
        name: 'Scott Robinson',
        age: 28,
        twitter: '@ScottWRobinson'
    });
    
    var elon = User.create({
        name: 'Elon Musk',
        age: 44,
        twitter: '@elonmusk'
    });
    
    connect('nedb://memory').then(function(db) {
        return Promise.all([scott.save(), elon.save()]);
    }).then(function(users) {
        users.forEach(function(u) {
            console.log('Saved user:', u.firstName);
        });
    
        return elon.delete();
    }).then(function() {
        console.log('Deleted Elon!')
    });
    
    // Prints to console...
    //
    // Saved user: Scott
    // Saved user: Elon
    // Deleted Elon!
    

    Hay mucho m谩s en este ODM de lo que he mostrado aqu铆. Para obtener m谩s informaci贸n, consulte este art铆culo o el README del proyecto para la documentaci贸n.

    Conclusi贸n

    Dado que NeDB es bastante peque帽o (隆y bastante r谩pido!), Es muy f谩cil agregarlo a casi cualquier proyecto. Y con Camo en la mezcla, solo necesitas unas pocas l铆neas de c贸digo para declarar objetos basados 鈥嬧媏n clases que son mucho m谩s f谩ciles de crear, eliminar y manipular.

    Si alguna vez ha utilizado NeDB en uno de sus proyectos, nos encantar铆a saberlo. 隆H谩znoslo saber en los comentarios!

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *