JavaScript >> Javascript 文檔 >  >> JavaScript

NeDB:輕量級 JavaScript 數據庫

當您想到數據庫時,首先想到的可能是 MySQL、MongoDB 或 PostgreSQL。雖然這些都是存儲數據的絕佳選擇,但它們對於大多數應用程序來說都過於強大了。

考慮使用 JavaScript 中的 Electron 框架編寫的桌面聊天應用程序。雖然聊天數據(消息、聯繫人、歷史記錄等)可能來自 API 服務器,但也需要本地存儲在應用程序中。您可能有數千條消息,所有這些消息都需要存儲起來以便於訪問和搜索。

所以你會怎麼做?一種選擇是將所有這些數據存儲在某個文件中,並在每次需要檢索它時進行搜索,但這可能效率低下。另一種選擇是不要在本地緩存數據,而是在每次需要更多數據時調用 API 服務器,但這樣你的應用程序的響應速度就會降低,並且會消耗更多的網絡數據。

一個更好的主意是使用嵌入式/輕量級數據庫,例如 NeDB。這更有意義,因為您的應用不會為成千上萬的用戶提供服務或處理千兆字節的數據。

NeDB 很像 SQLite,因為它是一個更大的數據庫系統的更小、可嵌入的版本。 NeDB 不是一個更小的 SQL 數據存儲,而是一個模仿 MongoDB 的更小的 NoSQL 數據存儲。

輕量級數據庫通常將其數據存儲在內存中或純文本文件中(帶有用於快速查找的索引)。這有助於減少系統上數據庫的總體佔用空間,非常適合小型應用程序。相比之下,MySQL tar 文件(Mac OSX)為 337MB,而 NeDB(未壓縮,未壓縮)只有 1.5MB 左右。

NeDB 最大的優點之一就是它的 API 是 MongoDB API 的一個子集,所以如果您熟悉 MongoDB,那麼在初始設置後使用 NeDB 應該沒有問題。

注意 :從 v1.8.0 開始,NeDB 還沒有更新到 Mongo 的一些新方法名,比如 insertOne , insertMany 並刪除 findOne .

NeDB 入門

首先,使用 NPM 安裝模塊:

$ npm install nedb --save

該模塊是用純 JavaScript 編寫的,因此編譯本機插件應該不會像 MongoDB 驅動程序那樣出現任何問題。

如果您打算在瀏覽器中使用它,請使用 Bower 安裝:

$ bower install nedb

與所有數據庫客戶端一樣,第一步是連接到後端數據庫。但是,在這種情況下,沒有要連接的外部應用程序,因此我們只需要告訴它您數據的位置。使用 NeDB,您可以通過多種方式保存數據。第一種選擇是將數據保存在內存中:

var Datastore = require('nedb');
var db = new Datastore();

// Start issuing commands right away...

這將使您一開始沒有數據,當您退出應用程序時,所有保存的數據都將丟失。雖然它非常適合在測試或較短的會話期間使用(例如在瀏覽器中)。

或者另一種選擇是將數據保存到文件中。這裡的區別是需要指定文件位置並加載數據。

var Datastore = require('nedb');
var db = new Datastore({ filename: 'path/to/your/file' });

db.loadDatabase(function(err) {
    // Start issuing commands after callback...
});

如果您不想調用 db.loadDatabase 對於您加載的每個數據庫,您始終可以使用 autoload: true 選項也是如此。

需要注意的重要一點是,每個文件都相當於 MongoDB 中的一個集合。因此,如果您有多個集合,則需要在啟動時加載多個文件。所以你的代碼可能是這樣的:

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

保存數據

從文件加載數據(或創建內存存儲)後,您需要開始保存數據。

很像 Mongo 驅動程序,您將使用 insert 創建一個新文檔:

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"

免費電子書:Git Essentials

查看我們的 Git 學習實踐指南,其中包含最佳實踐、行業認可的標準以及隨附的備忘單。停止谷歌搜索 Git 命令並真正學習 它!

這種插入可以很容易地擴展為一次保存多個文檔。使用相同的方法,只需傳遞一個對像數組,每個對像都會被保存並在回調中返回給你:

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

更新現有文檔的工作方式大致相同,只是您需要提供一個查詢來告訴系統哪些文檔需要更新。

加載數據

現在我們已經保存了一堆數據,是時候從數據庫中檢索它了。同樣,我們將遵循與 Mongo 相同的約定,使用 find 方法:

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

同樣,我們可以使用類似的操作來檢索多個文檔。返回的數據只是一個匹配文檔的數組:

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

您可能已經從最後一個代碼示例中註意到,正如您所期望的,NeDB 能夠進行更複雜的查詢,例如數字比較。以下運算符都可用於查找/匹配文檔:

  • $lt , $lte :小於、小於或等於
  • $gt , $gte :大於、大於或等於
  • $in :數組中包含的值
  • $nin :值不包含在數組中
  • $ne :不相等
  • $exists :檢查給定屬性的存在(或不存在)
  • $regex :用正則表達式匹配一個屬性的字符串

您還可以使用標準的排序、限制和跳過操作。如果沒有給 find 回調 方法,然後是 Cursor 對象將被返回給您,然後您可以將其用於排序、限制和跳過。下面是一個按名稱按字母順序排序的示例:

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

其他兩個操作,跳過和限制,與此非常相似。

find 支持的運算符還不少 和 findOne 方法,但我們不會在這裡全部介紹。您可以在 README 的查找文檔部分詳細了解這些操作的其餘部分。

刪除數據

除了與 find 類似,刪除數據沒什麼好說的 方法。您將使用相同類型的查詢在數據庫中查找相關文檔。然後刪除那些找到的。

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)

默認情況下,remove 方法只刪除一個文檔。為了通過一次調用刪除多個文檔,您必須設置 multi 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)

索引數據

就像任何其他數據庫一樣,您可以為數據設置索引以加快檢索速度或強制執行某些約束,例如唯一值。要創建索引,請使用 ensureIndex 方法。

目前支持的三種索引是:

  • unique :確保給定字段在整個集合中是唯一的
  • sparse :不要索引未定義給定字段的文檔
  • expireAfterSeconds :在給定的秒數(生存時間,或 TTL)後刪除文檔

在我看來,TTL 索引特別有用,因為它使您不必編寫代碼來頻繁掃描和刪除已過期的數據。

例如,這對於密碼重置請求很有用。如果您有 PasswordReset 存儲在數據庫中的對象,您不希望它永遠有效。為了幫助保護用戶,它可能會在幾天后過期並被刪除。這個 TTL 索引可以為你處理刪除它。

在下面的示例中,我們放置了 unique 限製文檔的 Twitter 句柄。這意味著如果一個用戶與另一個用戶使用相同的 Twitter 句柄保存,則會引發錯誤。

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

更進一步

雖然 NeDB API 易於使用且一切都很好,但如果沒有經過深思熟慮和組織,您的代碼可能會變得非常難以使用。這就是對象文檔映射器(類似於 ORM)發揮作用的地方。

使用 Camo ODM(我創建的),您可以簡單地將 NeDB 數據存儲視為 JavaScript 類。這允許您指定模式、驗證數據、擴展模式等。 Camo 甚至還可以與 MongoDB 一起使用,因此您可以在測試/開發環境中使用 NeDB,然後將 Mongo 用於您的生產系統,而無需更改任何代碼。

下面是一個連接數據庫、聲明類對象和保存一些數據的簡單示例:

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!

這個 ODM 比我在這裡展示的要多得多。有關詳細信息,請查看本文或項目的 README 文檔。

結論

NeDB 非常小(而且非常快!),很容易將它添加到幾乎任何項目中。再加上 Camo,您只需要幾行代碼即可聲明基於類的對象,這些對象更易於創建、刪除和操作。

如果您曾經在您的某個項目中使用過 NeDB,我們很想听聽。請在評論中告訴我們!


Tutorial JavaScript 教程
  1. Elasticsearch 初學者指南

  2. 🔥 在 JavaScript 中創建數字範圍

  3. 如何生成一個範圍內的隨機數但排除一些?

  4. JavaScript,如何獲取對象的類名

  5. 使用這些擴展和工具成為 VS Code Ninja [2020]

  6. Rxjs 轉換和過濾運算符

  7. 在 C# ClearScript 項目中動態添加程序集

  1. Scopes 起重裝置 |棘手的面試問題

  2. FoalTS 2022 調查開放!

  3. Next.JS 教程:通過 Next &Sanity 構建像亞馬遜一樣的電子商務

  4. 按鈕或鏈接 - 選擇哪個?

  5. 設置 React + Typescript 故事書設計系統的快速指南

  6. Firebase firestore 雲函數顯示錯誤:無效使用類型“未定義”作為 Firestore 參數

  7. 在 ES6 和 Canvas 上一步一步的俄羅斯方塊

  1. 使用 CSS 變量的暗/亮網站主題

  2. React v16.7 中的新功能 - 鉤子

  3. 如何開始使用 Vuetify

  4. GraphQL 的現代 React.js 設置(使用 Vite 和 urql)