JavaScript technologies

Persistence layers

Horváth, Győző
senior lecturer
horvath.gyozo@inf.elte.hu

Financed from the financial support ELTE won from the Higher Education Restructuring Fund of the Hungarian Government

Table of contents

  • Server side persistence
    • files (NeDB)
    • database (MongoDB, Mongoose)
  • Client side persistence
    • localStorage

Persisting state to files

Native file operations

fs modul

  • Asynchronous
    • fs.readFile()
    • fs.writeFile()
  • Synchronous
    • fs.readFileSync()
    • fs.writeFileSync()

NeDB

"Embedded datastore for node.js"

Github page of the project

npm install --save nedb

Some NeDB examples

var Datastore = require('nedb'),
    db = new Datastore({ filename: 'path/to/datafile', autoload: true });

//Inserting document(s)
db.insert(doc, function (err, newDoc) {   // Callback is optional
  // newDoc is the newly inserted document, including its _id
  // newDoc has no key called notToBeSaved since its value was undefined
});

//Finding document(s)
db.find({ foo: 'bar' }, function (err, docs) {
  // docs is an array containing documents Mars, Earth, Jupiter
  // If no document is found, docs is equal to []
});

db.findOne({ _id: 'id1' }, function (err, doc) {
  // doc is the document Mars
  // If no document is found, doc is null
});

//Replacing a document
db.update({ planet: 'Jupiter' }, { planet: 'Pluton'}, {}, function (err, numReplaced) {
  // numReplaced = 1
  // The doc #3 has been replaced by { _id: 'id3', planet: 'Pluton' }
  // Note that the _id is kept unchanged, and the document has been replaced
});

//Deleting a document
db.remove({ _id: 'id2' }, {}, function (err, numRemoved) {
  // numRemoved = 1
});

MongoDB

MongoDB

NoSQL database management system

Document-based

JSON/BSON documents

Basic concepts

Downloading and installing

  • Official page
    • version 2.x is available in standalone zip format
  • Extract to desktop (Windows)

Starting up

Server

<path to>\mongod.exe --dbpath "d:\test\mongo db data"

Client

<path to>\mongo.exe

Command-line interface

Documentation

> help
> use <dbname>
> db.<collection>.insert({ "apple" : "red" })
> db.<collection>.find()

MongoDB in Node.js

Installation

npm install --save mongodb

Usage (e.g. in a REST API)

var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var db;

MongoClient.connect('mongodb://localhost:27017/snippets', function (err, database) {
    if (err) throw err;
    db = database;
    console.log('Database connected');
});

router
    .get('/', function(req, res, next) {
        db.collection('snippets').find().toArray(function (err, docs) {
            res.json(docs);
        })
    })
    .post('/', function(req, res) {
        db.collection('snippets').insert(req.body);
        res.end();
    });

module.exports = router;

Mongoose ORM

Project homepage

Schema --> Model --> Instance
             ↓           ↓
         collection  document
  • Collection
    • find, remove, update
  • Document
    • save, validate

Task

Rewrite the MongoClient example using Mongoose!

  1. Defining model in a separate file!
  2. Establishing connection to the database
  3. Serving endpoints

Defining model

var SnippetSchema = new mongoose.Schema({
    title: String,
    code: String,
    type: String,
    date: {type: Date, default: Date.now }
});

var SnippetModel = mongoose.model('Snippet', SnippetSchema);

Establishing connection to the database

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/snippets');
var db = mongoose.connection;

var Snippet = require('../models/snippet');

Serving endpoints

router
    .get('/', function(req, res, next) {
        Snippet.find({}, function (err, docs) {
            res.json(docs);
        });
    })
    .post('/', function(req, res) {
        var snippet = new Snippet(req.body);
        snippet.save();
        res.json(snippet);
    })
    .put('/:id', function (req, res) {
        var id = req.params.id;
        var doc = req.body;
        Snippet.findByIdAndUpdate(id, doc, function (err) {
            res.json(doc);
        });
    })
    .delete('/:id', function (req, res) {
        var id = req.params.id;
        Snippet.findByIdAndRemove(id, function(err, doc) {
            res.json(doc);
        })
    });

Client-side persistence

localStorage

Possibilities

  • HTML 5 Storage (Web Storage)
    • localStorage
    • sessionStorage
  • Web SQL Database (partially supported)
  • Indexed Database (IndexedDB)
  • File API (for storing binary files)

localStorage

Collection of key-value pairs (object)

Synchronous API

//Storing/writing
localStorage.apple = 'red';
localStorage['anything'] = 42;

//Taking out/reading (even after reloading)
console.log(localStorage.apple);
console.log(localStorage['anything']);

String format is preferred

//Storing a complex data structure
var x = [1, 3, 5, 7];
localStorage.setItem('data', JSON.stringify(x));
var x2 = JSON.parse( localStorage.getItem('data') );

localStorage in frameworks

Backbone

// Importing
import LocalStorage from 'backbone.localstorage';

// Collections
var SomeCollection = Backbone.Collection.extend({

  localStorage: new LocalStorage("SomeCollection"), 

  // ...
});

Task

Save the data to the browser in the code snippet application using localStorage (there is no need for fixtures anymore)!

return Backbone.Collection.extend({
        
    localStorage: new Backbone.LocalStorage("CodeSnippets"),

    model: CodeSnippet,
    
    // ...
});