Original tutorial address
Nedb -- Node embedded database
Simple demo
<template> <div> <el-button type="primary" @click="addOneUser">Add user</el-button> <el-button type="primary" @click="search">query</el-button> </div> </template> <script> // Import related methods import Datastore from 'nedb'; let db = new Datastore({ filename: './db/user.db', autoload: true }); export default { data() { return { }; }, methods: { // Add a user addOneUser() { db.loadDatabase(function (err) { // Callback function (optional) console.error('nedb Load failed:', err); }); let doc = { name: 'Da San Zhang', age: 15 }; db.insert(doc, function (err, newDoc) { if(err) { console.log('Insert failed!'); }else{ console.log('success:',newDoc); } }); }, // Query user list search() { db.find({}, function (err, docs) { if(!err) { console.log(docs); } }); } } }; </script> <style scoped lang="scss"> </style>
There is a problem here. The database address is specified, but the data is directly saved in memory and can only be output by printing on the console.
Then I create a node demo separately. The data will be saved locally, but there is a problem. The data is saved in the same level directory of the file where the insert command is executed.
Basic use
brief introduction
NeDB is a NoSQL embedded database operation module implemented by Nodejs. It can be used as an in memory database, can also be used to realize local storage, and can even be used in the browser. The query method is flexible and supports the use of regular, comparison operators, logical operators, indexes and JSON depth queries.
NeDB is embedded into the application process, eliminating the overhead related to client server configuration. At runtime, it only needs less memory overhead, and is written with simplified code, which is faster. Its API is a subset of MongoDB, which can easily manage application data through these interfaces without relying on the original document files.
It has the characteristics of simplicity, light weight and fast speed. Because the total amount of data stored in the embedded database should be controlled within 1GB, it is suitable for application systems that do not need a lot of data processing.
install
npm install nedb --save
Create database
new Datastore(options)
effect:
Initializing a data store is equivalent to a set of MongoDB and a table of Mysql.
options object configuration parameters:
① Filename (optional): data storage file path. If it is empty, the data will be automatically stored in memory. Note that the path cannot end with '~'.
② Inmemoryonly (optional, false by default): data storage method. Whether it exists only in memory.
③ loadDatabase: load data into memory.
④ Timestampdata (optional, false by default): automatically generates timestamps with the fields createdAt and updateAt, which are used to record the time points of document insertion and update operations.
⑤ Autoload (optional, default false): if autoload is used, when the data store is created, the data will be automatically loaded from the file into memory without calling loadDatabase. Note that all command operations will not be executed until the data is loaded.
⑥ Onload (optional): it is called after the data is loaded, that is, it is triggered after the loadDatabase method is called. This method has an error parameter. If autoload is tried and this method is not defined, an error will be thrown by default during data loading.
⑦ After serialization (optional): this method can be used to convert data after it is serialized into a string and before it is written to disk. For example, you can do some data encryption. The input parameter of this method is a string (it must not contain the character "\ n", otherwise the data will be lost) and returns the converted string.
⑧ Before deserialization (optional): opposite to after serialization. Two must appear in pairs, otherwise it will cause data loss, which can be understood as an encryption and decryption process.
⑨ Corruptalertthreshold (optional): the default value is 10%, and the value is between 0-1. If the data file corruption rate exceeds this percentage, NeDB will not start. Taking 0 means that any data corruption cannot be tolerated; Taking 1 means ignoring the problem of data corruption.
⑩ Comparestrings (optional): compareStrings(a, b) compares two strings and returns - 1, 0, or 1. If defined, the default string comparison method will be overwritten to be compatible with the default method and cannot compare non US characters.
Note: if local storage is used and the autoload parameter is not configured, the loadDatabase method needs to be called manually. All operations (insert, find, update, remove) will not be executed before the method is called. Also, if loadDatabase fails, all commands will not be executed.
// Example 1: in memory database (it is not necessary to call the loadDatabase method) var Datastore = require('nedb'), db = new Datastore(); // Example 2: local storage needs to manually call the loadDatabase method var Datastore = require('nedb'), db = new Datastore({ filename: 'path/to/datafile' }); db.loadDatabase(function (err) { // Callback function (optional) // Now commands will be executed }); // Example 3: local storage with autoload configuration item var Datastore = require('nedb'), db = new Datastore({ filename: 'path/to/datafile', autoload: true }); // You can issue commands right away // Example 4: create multiple data stores db = {}; db.users = new Datastore('path/to/users.db'); db.robots = new Datastore('path/to/robots.db'); // If autoload is not configured, the database needs to be loaded (this method is asynchronous) db.users.loadDatabase(); db.robots.loadDatabase();
insert
db.insert()
db.insert(doc, callback)
effect:
It is equivalent to inserting a record in a mysql document table. If the document does not contain_ id field, NeDB will automatically generate a numeric string with a length of 16 characters. Once this field is determined, it cannot be changed.
Parameters:
doc: supports String, Number, Boolean, Date, null, array and object types. If the field is of undefined type, it will not be saved. The processing method here is a little different from that of MongoDB. MongoDB will convert undefined to null for storage. Field names cannot start with "$" or contain "'.
Callback (optional): callback function, including parameters err and newDoc. Err is an error, and newDoc is a newly inserted document, including its_ id field.
var doc = { hello: 'world' , n: 5 , today: new Date() , nedbIsAwesome: true , notthere: null , notToBeSaved: undefined // This field will not be saved , fruits: [ 'apple', 'orange', 'pear' ] , infos: { name: 'nedb' } }; 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 }); // Use array to realize batch insertion. Once one of the operations fails, all changes will be rolled back. db.insert([{ a: 5 }, { a: 42 }], function (err, newDocs) { // Two documents were inserted in the database // newDocs is an array with these documents, augmented with their _id }); // If the a field has a uniqueness constraint, the operation will fail. db.insert([{ a: 5 }, { a: 42 }, { a: 5 }], function (err) { // err is a 'uniqueViolated' error // The database was not modified });
query
db.find()
db.find(query, callback)
effect:
Query qualified document sets.
Parameters:
Query: object type, query criteria. Support the use of comparison operators ($lt, $lte, $gt, $gte, $in, $nin,
n
e
)
,
Logic
Compilation
transport
count
symbol
(
ne), logical operator(
ne), logical operators (or, $and, $not, $where) and regular expressions.
Callback (optional): callback function, including parameters err and docs. Err is an error and Docs is the queried document set.
// Data storage collection // { _id: 'id1', planet: 'Mars', system: 'solar', inhabited: false, satellites: ['Phobos', 'Deimos'] } // { _id: 'id2', planet: 'Earth', system: 'solar', inhabited: true, humans: { genders: 2, eyes: true } } // { _id: 'id3', planet: 'Jupiter', system: 'solar', inhabited: false } // { _id: 'id4', planet: 'Omicron Persei 8', system: 'futurama', inhabited: true, humans: { genders: 7 } } // { _id: 'id5', completeData: { planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] } } // Example 1: basic query. Regular expressions can be used to match strings. Use "." Match the elements in the object or array. // Single field query db.find({ system: 'solar' }, function (err, docs) { }); // Regular expression query db.find({ planet: /ar/ }, function (err, docs) { // docs contains Mars and Earth }); // Multi condition query db.find({ system: 'solar', inhabited: true }, function (err, docs) { // docs is an array containing document Earth only }); // Query by object attribute db.find({ "humans.genders": 2 }, function (err, docs) { // docs contains Earth }); // Query based on array object properties db.find({ "completeData.planets.name": "Mars" }, function (err, docs) { // docs contains document 5 }); db.find({ "completeData.planets.name": "Jupiter" }, function (err, docs) { // docs is empty }); db.find({ "completeData.planets.0.name": "Earth" }, function (err, docs) { // docs contains document 5 // If we had tested against "Mars" docs would be empty because we are matching against a specific array element }); // Object depth comparison query, do not compare with "." Use confusion db.find({ humans: { genders: 2 } }, function (err, docs) { // docs is empty, because { genders: 2 } is not equal to { genders: 2, eyes: true } }); // Query all result sets db.find({}, function (err, docs) { }); // Query a document db.findOne({ _id: 'id1' }, function (err, doc) { // doc is the document Mars // If no document is found, doc is null }); // Example 2: {field: {$op: value}} ($op stands for any comparison operator) // $lt, $lte: less than, less than or equal to // $gt, $gte: greater than or equal to // $in: belongs to // $ne, $nin: not equal to, not belonging to // $exists: the value is true or false, which is used to detect whether the document has a field // $regex: detect whether the string matches the regular expression // $lt, $lte, $gt and $gte can only be used for numeric and string types db.find({ "humans.genders": { $gt: 5 } }, function (err, docs) { // docs contains Omicron Persei 8, whose humans have more than 5 genders (7). }); // When comparing strings, dictionary order is used. db.find({ planet: { $gt: 'Mercury' }}, function (err, docs) { // docs contains Omicron Persei 8 }) // Using $in. $nin is used in the same way db.find({ planet: { $in: ['Earth', 'Jupiter'] }}, function (err, docs) { // docs contains Earth and Jupiter }); // Using $exists db.find({ satellites: { $exists: true } }, function (err, docs) { // docs contains only Mars }); // Using $regex with another operator db.find({ planet: { $regex: /ar/, $nin: ['Jupiter', 'Earth'] } }, function (err, docs) { // docs only contains Mars because Earth was excluded from the match by $nin }); // Example 3: when a field in the document is an array, NeDB will first judge whether the query value is an array. If it is an array, it will perform an accurate search, and then judge whether there is an array comparison method (now only $size and $elemmatch are supported). If none, all elements will be queried. // $size: matches the size of the array // $elemMatch: matches at least one array element // Exact search db.find({ satellites: ['Phobos', 'Deimos'] }, function (err, docs) { // docs contains Mars }) db.find({ satellites: ['Deimos', 'Phobos'] }, function (err, docs) { // docs is empty }) // Using array comparison method // The $elemMatch operator will match the elements in the array that meet all conditions db.find({ completeData: { planets: { $elemMatch: { name: 'Earth', number: 3 } } } }, function (err, docs) { // docs contains documents with id 5 (completeData) }); db.find({ completeData: { planets: { $elemMatch: { name: 'Earth', number: 5 } } } }, function (err, docs) { // docs is empty }); // Using comparison operators in $elemMatch db.find({ completeData: { planets: { $elemMatch: { name: 'Earth', number: { $gt: 2 } } } } }, function (err, docs) { // docs contains documents with id 5 (completeData) }); // Note that nested operators cannot be used. E.g. {$size: {$LT: 5}} will throw an exception db.find({ satellites: { $size: 2 } }, function (err, docs) { // docs contains Mars }); db.find({ satellites: { $size: 1 } }, function (err, docs) { // docs is empty }); // If a document's field is an array, matching it means matching any element of the array db.find({ satellites: 'Phobos' }, function (err, docs) { // docs contains Mars. Result would have been the same if query had been { satellites: 'Deimos' } }); // This also works for queries that use comparison operators db.find({ satellites: { $lt: 'Amos' } }, function (err, docs) { // docs is empty since Phobos and Deimos are after Amos in lexicographical order }); // This also works with the $in and $nin operator db.find({ satellites: { $in: ['Moon', 'Deimos'] } }, function (err, docs) { // docs contains Mars (the Earth document is not complete!) }); // Example 4: logical operators $or, $and, $not, $where // $or, $and: Union, intersection {$op: [query1, query2,...]} // $not: take non - {$not: query} // $where: condition {$where: function() {/ * object is "this", return a Boolean * /}} db.find({ $or: [{ planet: 'Earth' }, { planet: 'Mars' }] }, function (err, docs) { // docs contains Earth and Mars }); db.find({ $not: { planet: 'Earth' } }, function (err, docs) { // docs contains Mars, Jupiter, Omicron Persei 8 }); db.find({ $where: function () { return Object.keys(this) > 6; } }, function (err, docs) { // docs with more than 6 properties }); // You can mix normal queries, comparison queries and logical operators db.find({ $or: [{ planet: 'Earth' }, { planet: 'Mars' }], inhabited: true }, function (err, docs) { // docs contains Earth }); // Example 5: Projects // In the second parameter, pass in the projects object to specify the return field. For example: {a:1, b:1} specifies to return only a and b fields, {a:0, b:0} specifies to omit a and b fields. // _ ID is returned by default, and the setting does not need to be returned_ id: 0 // Same database as above // Keeping only the given fields db.find({ planet: 'Mars' }, { planet: 1, system: 1 }, function (err, docs) { // docs is [{ planet: 'Mars', system: 'solar', _id: 'id1' }] }); // Keeping only the given fields but removing _id db.find({ planet: 'Mars' }, { planet: 1, system: 1, _id: 0 }, function (err, docs) { // docs is [{ planet: 'Mars', system: 'solar' }] }); // Omitting only the given fields and removing _id db.find({ planet: 'Mars' }, { planet: 0, system: 0, _id: 0 }, function (err, docs) { // docs is [{ inhabited: false, satellites: ['Phobos', 'Deimos'] }] }); // Failure: using both modes at the same time db.find({ planet: 'Mars' }, { planet: 0, system: 1 }, function (err, docs) { // err is the error message, docs is undefined }); // You can also use it in a Cursor way but this syntax is not compatible with MongoDB db.find({ planet: 'Mars' }).projection({ planet: 1, system: 1 }).exec(function (err, docs) { // docs is [{ planet: 'Mars', system: 'solar', _id: 'id1' }] }); // Project on a nested document db.findOne({ planet: 'Earth' }).projection({ planet: 1, 'humans.genders': 1 }).exec(function (err, doc) { // doc is { planet: 'Earth', _id: 'id2', humans: { genders: 2 } } }); // Example 6: sorting and paging // Document set // doc1 = { _id: 'id1', planet: 'Mars', system: 'solar', inhabited: false, satellites: ['Phobos', 'Deimos'] } // doc2 = { _id: 'id2', planet: 'Earth', system: 'solar', inhabited: true, humans: { genders: 2, eyes: true } } // doc3 = { _id: 'id3', planet: 'Jupiter', system: 'solar', inhabited: false } // doc4 = { _id: 'id4', planet: 'Omicron Persei 8', system: 'futurama', inhabited: true, humans: { genders: 7 } } // No query used means all results are returned (before the Cursor modifiers) db.find({}).sort({ planet: 1 }).skip(1).limit(2).exec(function (err, docs) { // docs is [doc3, doc1] }); // You can sort in reverse order like this db.find({ system: 'solar' }).sort({ planet: -1 }).exec(function (err, docs) { // docs is [doc1, doc3, doc2] }); // You can sort on one field, then another, and so on like this: db.find({}).sort({ firstField: 1, secondField: -1 }) ... // You understand how this works!
to update
db.update()
db.update(query, update, options, callback)
effect:
Update the result set matched to query according to the rules of the update parameter.
Parameters:
Query: consistent with the usage of the query parameter in find and findOne
update: Specifies the document change rule. This parameter can be a new document or a set of modifiers, which cannot be used at the same time. When using modifiers, if the field to be changed does not exist, it will be created automatically. Available modifiers are $set (change field value), $unset (delete a field), $Inc (add a field),
m
i
n
/
min/
Min / max (change the field value, the incoming value needs to be less than / greater than the current value), and some modifiers used on the array, $push, $pop, $addTopSet, $pull, $each, $slice. The specific usage is as follows.
options: object type. Muti (false by default), whether multiple documents can be modified; Upsert (false by default). If the query does not match the result set, there are two situations to consider. One is that update is a simple object (without any modifiers), the other is with modifiers. In the first case, the document will be directly inserted, and in the second case, the document changed by the modifiers will be inserted;
Callback (optional): parameters (err, numAffected, affectedDocuments, upsert). numAffected: number of affected documents; Affected documents: updated documents.
Note:_ id cannot be modified
// Document set // { _id: 'id1', planet: 'Mars', system: 'solar', inhabited: false } // { _id: 'id2', planet: 'Earth', system: 'solar', inhabited: true } // { _id: 'id3', planet: 'Jupiter', system: 'solar', inhabited: false } // { _id: 'id4', planet: 'Omicron Persia 8', system: 'futurama', inhabited: true } // Replace one document with another 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 // (the 'system' and inhabited fields are not here anymore) }); // Set the value of a saved field db.update({ system: 'solar' }, { $set: { system: 'solar system' } }, { multi: true }, function (err, numReplaced) { // numReplaced = 3 // Field 'system' on Mars, Earth, Jupiter now has value 'solar system' }); // Set a value for a field that does not exist db.update({ planet: 'Mars' }, { $set: { "data.satellites": 2, "data.red": true } }, {}, function () { // Mars document now is { _id: 'id1', system: 'solar', inhabited: false // , data: { satellites: 2, red: true } // } // Not that to set fields in subdocuments, you HAVE to use dot-notation // Using object-notation will just replace the top-level field db.update({ planet: 'Mars' }, { $set: { data: { satellites: 3 } } }, {}, function () { // Mars document now is { _id: 'id1', system: 'solar', inhabited: false // , data: { satellites: 3 } // } // You lost the "data.red" field which is probably not the intended behavior }); }); // Delete a field db.update({ planet: 'Mars' }, { $unset: { planet: true } }, {}, function () { // Now the document for Mars doesn't contain the planet field // You can unset nested fields with the dot notation of course }); // Set up upsert db.update({ planet: 'Pluton' }, { planet: 'Pluton', inhabited: false }, { upsert: true }, function (err, numReplaced, upsert) { // numReplaced = 1, upsert = { _id: 'id5', planet: 'Pluton', inhabited: false } // A new document { _id: 'id5', planet: 'Pluton', inhabited: false } has been added to the collection }); // If you upsert with a modifier, the upserted doc is the query modified by the modifier // This is simpler than it sounds :) db.update({ planet: 'Pluton' }, { $inc: { distance: 38 } }, { upsert: true }, function () { // A new document { _id: 'id5', planet: 'Pluton', distance: 38 } has been added to the collection }); // If we insert a new document { _id: 'id6', fruits: ['apple', 'orange', 'pear'] } in the collection, // let's see how we can modify the array field atomically // $push inserts new elements at the end of the array db.update({ _id: 'id6' }, { $push: { fruits: 'banana' } }, {}, function () { // Now the fruits array is ['apple', 'orange', 'pear', 'banana'] }); // $pop removes an element from the end (if used with 1) or the front (if used with -1) of the array db.update({ _id: 'id6' }, { $pop: { fruits: 1 } }, {}, function () { // Now the fruits array is ['apple', 'orange'] // With { $pop: { fruits: -1 } }, it would have been ['orange', 'pear'] }); // $addToSet adds an element to an array only if it isn't already in it // Equality is deep-checked (i.e. $addToSet will not insert an object in an array already containing the same object) // Note that it doesn't check whether the array contained duplicates before or not db.update({ _id: 'id6' }, { $addToSet: { fruits: 'apple' } }, {}, function () { // The fruits array didn't change // If we had used a fruit not in the array, e.g. 'banana', it would have been added to the array }); // $pull removes all values matching a value or even any NeDB query from the array db.update({ _id: 'id6' }, { $pull: { fruits: 'apple' } }, {}, function () { // Now the fruits array is ['orange', 'pear'] }); db.update({ _id: 'id6' }, { $pull: { fruits: $in: ['apple', 'pear'] } }, {}, function () { // Now the fruits array is ['orange'] }); // $each can be used to $push or $addToSet multiple values at once // This example works the same way with $addToSet db.update({ _id: 'id6' }, { $push: { fruits: { $each: ['banana', 'orange'] } } }, {}, function () { // Now the fruits array is ['apple', 'orange', 'pear', 'banana', 'orange'] }); // $slice can be used in cunjunction with $push and $each to limit the size of the resulting array. // A value of 0 will update the array to an empty array. A positive value n will keep only the n first elements // A negative value -n will keep only the last n elements. // If $slice is specified but not $each, $each is set to [] db.update({ _id: 'id6' }, { $push: { fruits: { $each: ['banana'], $slice: 2 } } }, {}, function () { // Now the fruits array is ['apple', 'orange'] }); // $min/$max to update only if provided value is less/greater than current value // Let's say the database contains this document // doc = { _id: 'id', name: 'Name', value: 5 } db.update({ _id: 'id1' }, { $min: { value: 2 } }, {}, function () { // The document will be updated to { _id: 'id', name: 'Name', value: 2 } }); db.update({ _id: 'id1' }, { $min: { value: 8 } }, {}, function () { // The document will not be modified });
delete
db.remove()
db.remove(query, options, callback)
effect:
Delete all document sets matched by query according to the options configuration.
Parameters:
Query: consistent with the usage of the query parameter in find and findOne
options: only one is available. Muti (default false), which allows multiple documents to be deleted.
callback: optional, parameters: err, numRemoved
// Document set // { _id: 'id1', planet: 'Mars', system: 'solar', inhabited: false } // { _id: 'id2', planet: 'Earth', system: 'solar', inhabited: true } // { _id: 'id3', planet: 'Jupiter', system: 'solar', inhabited: false } // { _id: 'id4', planet: 'Omicron Persia 8', system: 'futurama', inhabited: true } // Delete a record // options set to {} since the default for multi is false db.remove({ _id: 'id2' }, {}, function (err, numRemoved) { // numRemoved = 1 }); // Delete multiple records db.remove({ system: 'solar' }, { multi: true }, function (err, numRemoved) { // numRemoved = 3 // All planets from the solar system were removed }); // Delete all records db.remove({}, { multi: true }, function (err, numRemoved) { });
Indexes
db.ensureIndex()
db.ensureIndex(options, callback)
effect:
NeDB supports indexing. Index can improve query speed and ensure the uniqueness of fields. Indexes can be used in any field, including deeply nested fields. At present, indexes can only be used to speed up basic queries and queries using $in, $lt, $lte, $gt and $gte operators, as shown in the example in the find interface above. Ensure that the index is not an array object. Method can be called at any time. It is recommended to call it when the application starts (this method is synchronous, and it only takes 35ms to add an index to 1000 documents).
Parameters:
Fieldname (required): index field, use "." Reference nested fields.
Unique (optional, default false): field uniqueness constraint. Note: uniqueness constraints increase the error of adding indexes to fields that are not defined in two documents.
Spark (optional, default false): can't quote for undefined fields. If you accept adding indexes to fields not defined in multiple documents, you need to use this configuration parameter with unique.
Expireafterseconds (optional, seconds): TTL index, set the automatic expiration time.
Delete index: dB removeIndex(fieldName, cb)
Note:_ The id field will be automatically indexed and unique, so you don't have to use ensureIndex for it. If local storage is used, the index will also be saved in the data file. When the database is loaded the second time, the index will also be added automatically. If you load a database that already has an index, deleting the index will have no effect.
db.ensureIndex({ fieldName: 'somefield' }, function (err) { // If there was an error, err is not null }); // Index pair uniqueness constraint setting db.ensureIndex({ fieldName: 'somefield', unique: true }, function (err) { }); // Using a sparse unique index db.ensureIndex({ fieldName: 'somefield', unique: true, sparse: true }, function (err) { }); // Use uniqueness constraints to make errors. Check the format of err db.insert({ somefield: 'nedb' }, function (err) { // err is null db.insert({ somefield: 'nedb' }, function (err) { // err is { errorType: 'uniqueViolated' // , key: 'name' // , message: 'Unique constraint violated for key name' } }); }); // Remove the index of somefield field field db.removeIndex('somefield', function (err) { }); // Example of using expireAfterSeconds to remove documents 1 hour // after their creation (db's timestampData option is true here) db.ensureIndex({ fieldName: 'createdAt', expireAfterSeconds: 3600 }, function (err) { }); // You can also use the option to set an expiration date like so db.ensureIndex({ fieldName: 'expirationDate', expireAfterSeconds: 0 }, function (err) { // Now all documents will expire when system time reaches the date in their // expirationDate field });
count
db.count()
// Count all planets in the solar system db.count({ system: 'solar' }, function (err, count) { // count equals to 3 }); // Count all documents in the datastore db.count({}, function (err, count) { // count equals to 4 });