An on disk database that indexes everything for fast querying.
npm install --save doubledb
import createDoubledb from 'doubledb';
const doubledb = await createDoubledb('./data');
// Insert a document
await doubledb.insert({
id: undefined, // defaults to uuid, must be unique
firstName: 'Joe',
lastName: 'Bloggs',
stats: {
wins: 10,
loses: 5
},
skills: ['cooking', 'running']
});
// Read operations
await doubledb.read(record.id);
await doubledb.find('firstName', 'Joe');
await doubledb.find('stats.wins', 10);
await doubledb.find('skills', 'cooking');
await doubledb.find('firstName', v => v.startsWith('J'), { skip: 20, gt: 'J', lt: 'K' });
await doubledb.filter('firstName', 'Joe');
await doubledb.filter('firstName', v => v.startsWith('J'));
await doubledb.filter('firstName', v => v.startsWith('J'), { limit: 10, skip: 20, gt: 'J', lt: 'K' });
// Update operations
await doubledb.upsert(record.id, { firstName: 'Joe', lastName: 'Bloggs' });
await doubledb.replace(record.id, { firstName: 'Joe', lastName: 'Bloggs' });
await doubledb.patch(record.id, { firstName: 'Bob' });
// Delete operation
await doubledb.remove(record.id);
// Batch operations
await doubledb.batchInsert([
{ firstName: 'Alice', lastName: 'Smith' },
{ firstName: 'Bob', lastName: 'Johnson' },
{ firstName: 'Charlie', lastName: 'Brown' }
]);
// Advanced querying
const users = await doubledb.query({
status: 'active',
age: { $gte: 18 }
}, {
limit: 10,
offset: 0,
sort: { lastName: 1 }
});
// Count documents
const totalUsers = await doubledb.count({ status: 'active' });
Get a single record by its .id
property.
If a record is found, the whole record will be returned.
If no record is found, undefined
will be returned.
Quickly find a single record by any field (use.dot.notation.for.nested.properties
) and its exact value.
If multiple records exist, a skip
option can be provided to ignore the first number
of finds.
If a record is found, the whole record will be returned.
If no record is found, undefined
will be returned.
Slow find a single record by any field and test against a matcherFunction
.
If multiple records exist:
- a
skip
option can be provided to ignore the firstnumber
of finds. - a
limit
option can be provided to stop afternumber
of finds.
Find using a matcherFunction will work without a gt
and lt
, but the indexing will be pretty useless, as it will need to scan every single record.
You should provide a gt
and/or lt
to let the indexer know where to begin/end.
For example:
// Will scan every record (slow)
doubledb.find('firstName', v => v.startsWith('Jo'))
// Better - starts from 'Jo'
doubledb.find('firstName', v => v.startsWith('Jo'), { gt: 'Jo' })
// Best - specify both start and end range
doubledb.find('firstName', v => v.startsWith('Jo'), { gt: 'Jo', lt: 'K' })
// More examples
doubledb.find('favouriteNumber', v => v > 5 && v < 10, { gt: 5, lt: 10 })
doubledb.find('firstName', v => ['Dave', 'Peter'].includes(v), { gt: 'Dave', lte: 'Peter' })
This works the exact same as .find
but will return an array of all matching records instead of just the first match.
If records are found, an array will be returned containing every complete found record. If no records are found, an empty array will be returned.
Completely replace a key with a new object, losing all previous fields in the record.
Merge the new object with the existing record.
Example:
// Existing record
{
"id": "1",
"firstName": "Joe",
"lastName": "Bloggs"
}
// After running:
await doubledb.patch('1', { fullName: 'Joe Bloggs' })
// Result:
{
"id": "1",
"firstName": "Joe",
"lastName": "Bloggs",
"fullName": "Joe Bloggs"
}
Remove a record by its id.
Query the database using a complex query object with support for multiple operators and conditions.
Example:
const records = await doubledb.query({
location: 'London',
age: { $gte: 18 },
$or: [
{ status: 'active' },
{ status: 'pending' }
]
}, {
limit: 10,
offset: 0,
sort: { lastName: 1 },
project: { firstName: 1, lastName: 1 }
});
$eq
: Equal to a value$ne
: Not equal to a value$gt
: Greater than a value$gte
: Greater than or equal to a value$lt
: Less than a value$lte
: Less than or equal to a value$in
: Value is in the provided array$nin
: Value is not in the provided array$all
: Array contains all the provided values$exists
: Field exists or does not exist$not
: Negates the condition$sw
: String starts with value
Count the number of documents matching the given query criteria. If no query object is provided, returns the total number of documents in the database.
Example:
// Count total documents
const total = await doubledb.count();
// Count documents matching a simple field value
const londonCount = await doubledb.count({ location: 'London' });
// Count using operators
const activeUsersCount = await doubledb.count({
status: 'active',
age: { $gte: 18 }
});
// Count with $or conditions
const count = await doubledb.count({
$or: [
{ category: 'A' },
{ category: 'B' }
]
});
The count method supports all the same operators as the query method. For optimal performance, it uses internal counters for simple queries, while complex queries may require scanning index entries.
Insert multiple documents at once for better performance.
Example:
await doubledb.batchInsert([
{ firstName: 'Alice', lastName: 'Smith' },
{ firstName: 'Bob', lastName: 'Johnson' },
{ firstName: 'Charlie', lastName: 'Brown' }
]);
If the documents are successfully inserted, an array of the inserted documents will be returned. If the documents array is empty, an error will be thrown.