-
Notifications
You must be signed in to change notification settings - Fork 185
API Reference
- API Convention
- memdb binaries
- memdb-client
- Connection
- AutoConnection
-
Collection
- coll.find(queryOrId[, fields][, opts]) -> document(s)
- coll.insert(docs) -> [doc._id]
- coll.update(queryOrId, modifier, opts) -> count
- coll.remove(queryOrId) -> count
- coll.findOne(queryOrId[, fields][, opts]) -> document
- coll.findById(id[, fields][, opts]) -> document
- coll.findReadOnly(queryOrId[, fields][, opts]) -> document(s)
- coll.findOneReadOnly(queryOrId[, fields][, opts]) -> document
- coll.findByIdReadOnly(id[, fields][, opts]) -> document
- coll.count(query) -> number
-
mdbgoose
-
API Changes
- Bluebird Promisified API
- mdbgooose.connect(opts)
- mdbgoose.disconnect()
- mdbgoose.transaction(func[, shardId]) -> result
- mdbgoose.genCollectionConfig() -> collectionsConfig (sync)
- Model.find
- Model.findOne
- Model.findById
- Model.findReadOnly
- Model.findOneReadOnly
- Model.findByIdReadOnly
- Model.count
- The following API is removed
- Schema
- Queries
- Access backend MongoDB
-
API Changes
- Restrictions
Unless explicitly stated, all API is async and returns a bluebird promise
You can use generator on node v0.12+ with --harmony option
var conn = yield memdb.connect(opts);
Or use promise on previous node version
memdb.connect(opts).then(function(conn){
// use conn here
});
The following is incorrect
var conn = memdb.connect(opts); //DO NOT DO THIS!
The memdb server
Usage
memdbd --shard=[shardId] [options]
Options
-
--shard
(required) - shardId to start -
--conf
- path. Memdb config file path. If not specified, the following paths will be searched in order [~/.memdb/memdb.conf.js, /etc/memdb.conf.js] -
--daemon
- start as daemon -
--help
- display help
Example
memdbd --shard=s1 --conf=memdb.js --daemon
To shutdown server, just press ^C when in console mode, or send signal kill to the process when in daemon mode.
Memdb server config file
/*
* MemDB config template
*
* Please modify it on your needs
*
* This is plain javascript, you can add any js code here, just export the config
*/
module.exports = {
// *** global settings for all shards ***
// Global backend storage, all shards must connect to the same mongodb (or mongodb cluster)
backend : {
engine : 'mongodb', // should be 'mongodb'
url : 'mongodb://localhost/memdb-test', // mongodb connect string
options : {}, // mongodb connect options
},
// Global locking redis, all shards must connect to the same redis (or redis cluster)
locking : {
host : '127.0.0.1',
port : 6379,
db : 0,
},
// Data replication redis, one redis instance for each shard
// You can override this in shard settings to choice different slave for each shard
slave : {
host : '127.0.0.1',
port : 6379,
db : 0,
},
// Log settings
log : {
// Log file path
path : '/tmp',
// Log Level (one of 'ALL', 'TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'OFF')
// Please set to WARN on production
level : 'WARN',
},
// Promise settings
promise : {
// Enable long stack trace, disable it on production
longStackTraces : false,
},
// user for memdbcluster ssh login, default current user
// when start using memdbcluster, make sure you have ssh permission (without password) on all servers,
// and the memdb version, install folder, config files are all the same in all servers
user : process.env.USER,
// Collection settings for index
collections : {
// Collection name
player : {
// Index setting, modify it on your need
indexes : [
{
// Index keys
keys : ['areaId'],
// Value exclude from index. Values like '', -1 occurs too often, which can make the index too large.
// 'null' or 'undefined' is ignored by default.
valueIgnore : {
areaId : ['', -1],
},
},
{
// Index keys (compound index)
keys : ['deviceType', 'deviceId'],
// Unique constraint for the index
unique : true,
},
]
}
},
// *** Shard specific settings ***
// This will override global settings on specifid shard
shards : {
// shardId
s1 : {
// server IP
host : '127.0.0.1',
// listen port
port : 31017,
// bind Ip
// DO NOT bind to localhost when deploy on multiple servers
// make sure servers can communicate with each other
bind : '0.0.0.0',
// Add any shard specific settings here
// slave : {
// host : '127.0.0.1',
// port : 6379,
// db : 1,
// },
},
// Add more shards
s2 : {
host : '127.0.0.1',
port : 31018,
},
}
// *** additional settings ***
// These settings are unstable and may change in later version
// Delay for flush changes to backend storage
// Set it to large value to improve performance if the data delay in backend storage is not an issue.
// persistentDelay : 600 * 1000, // number in ms, default 10 min. 0 indicates never
// Idle time before document is removed from memory.
// Larger value can improve performance but use more memory.
// Set it to large value if the documents accessed via this shard is limited.
// Do not access too many different documents in a short time, which may exhault memory and trigger heavy GC operation.
// idleTimeout : 1800 * 1000, // number in ms, default 30 min. 0 indicates never
// GC will be triggered when memory usage reach this limit
// GC can be very heavy, please adjust idleTimeout to avoid GC.
// memoryLimit : 1024, // number in MB, default 1024
// Disable redis replica, DO NOT turn on this in production.
// disableSlave : false, // default false
// Slow query time
// slowQuery : 2000, // number in ms. default 2000
// Turn on heapdump module (https://www.npmjs.com/package/heapdump)
// heapdump : false, // default false
};
Memdb interactive shell
The shell is just a nodejs repl, you can use all features provided by nodejs repl
Usage:
memdb [options]
Options:
-
-h, --host
- ip. shard ip -
-p, --port
- port. shard port -
-s, --shard
- shardId. -
-c, --conf
- path. config file path -
-h, --help
display help
Example:
memdb -h127.0.0.1 -p31017
memdb -s s1 -c memdb.conf.js
Play with shell
memdb> db.insert('player', {_id : 1, name : 'rain'}) // insert a doc to 'player' collection
'1'
memdb> db.find('player', 1) // find doc by id
{ _id: '1', name: 'rain' }
memdb> db.commit() // commit changes
true
memdb> db.update('player', 1, {$set : {name : 'snow'}}) // update doc
1
memdb> db.find('player', 1, 'name')
{ name: 'snow' }
memdb> db.rollback() // rollback changes
true
memdb> db.find('player', 1, 'name')
{ name: 'rain' }
memdb> db.remove('player', 1) // remove doc
1
memdb> db.commit()
true
memdb> db.info()
{
connId: '5e70898b-7349-4a05-8e0f-42fcad6a91e4', // connection id
ver: '0.4.0', // server version
uptime: 8.231, // start time in second
mem: { rss: 55701504, heapTotal: 35713792, heapUsed: 19789608 }, // nodejs memory usage
ops: [ 0, 0, 0 ], // operation per second in last 1, 5, 15 minutes
tps: [ 0, 0, 0 ], // transaction per second in last 1, 5, 15 minutes
lps: [ 0, 0, 0 ], // load(from backend) per second in last 1, 5, 15 minutes
ups: [ 0, 0, 0 ], // unload(to backend) per second in last 1, 5, 15 minutes
pps: [ 0, 0, 0 ], // persistent(to backend) per second in last 1, 5, 15 minutes
counter: { // performance counter
'find:player': [0, 0, 0], // 'method:collection' : [total time in ms, total count, average time in ms]
}
}
memdb> db.resetCounter() //reset performance counter
memdb> ^D (to exit)
Start memdb in cluster mode
When using memdbcluster, make sure you have ssh permission (without password) on all servers, and the memdb version, install folder, config files are all same in all servers
Usage
memdbcluster [command] [--conf=memdb.conf.js] [--shard=shardId]
Commands
-
start
- Start cluster -
stop
- Stop cluster -
status
- Show cluster status -
drop
- Drop all data
Options
-
--conf
- Memdb config file path -
--shard
(Optional) - Specify shardId. Will operate on all shards if not specified
Example
memdbcluster start
memdbcluster stop --shard=s1
memdbcluster status --conf=memdb.conf.js --shard=s1
Memdb index build tool. To update index on a non-empty database, or fix corrupted index data.
You must shutdown all shards before running memdbindex
Usage
memdbindex [rebuild | drop] [options]
Options
-
--conf
- Memdb config file path -
--coll
- collection name -
--keys
- index keys, split with '.'
Example
memdbindex rebuild --conf=memdb.js --coll=player --keys=areaId
// The specified index on coll and keys must defined in memdb.js
memdbindex drop --coll=player --keys=areaId
Memdb nodejs client library
var memdb = require('memdb-client');
Connect to memdb server
-
opts
- Connect options
{
host : '127.0.0.1',
port : 31017,
}
- Returns:
connection
Example
var conn = yield memdb.connect({host : '127.0.0.1', port : 31017});
Get autoConnection to memdb server
-
opts.shards
- Specify all shards host and port
{
shardId1 : {host : '127.0.0.1', port : 31017},
shardId2 : {host : '127.0.0.1', port : 31018},
}
- Returns:
autoConnection
Example
var shards = {
s1 : {host : '127.0.0.1', port : 31017},
s2 : {host : '127.0.0.1', port : 31018},
};
var autoconn = yield memdb.autoConnect({shards : shards});
Get mdbgoose instance
- Returns:
mdbgoose
var mdbgoose = memdb.goose;
Connect directly to backend mongodb, return mongodb's db
instance.
You can use full power of mongodb's query system, please note that the data returned from backend is NOT guaranteed to be up-to-date,
please adjust persistentDelay
option to decrease data delay.
DO NOT write directly to backend mongodb, which can break data consistency.
-
backend.url
- Mongodb connection string - Returns: Mongodb
db
instance
Example
var db = yield memdb.connectBackend({url : 'mongodb://localhost/test'});
var doc = yield db.collection('test').findOneAsync();
yield db.collection('test').removeAsync(); // Error! can not write
connection to memdb server
var conn = yield memdb.connect({host : '127.0.0.1', port : 31017});
Get collection by name
-
name
- Collection name - Returns:
collection
var collection = conn.collection('player');
Commit changes
yield conn.commit();
Rollback changes
yield conn.rollback();
Close connection
yield conn.close();
autoConnection to memdb server
var autoconn = yield memdb.autoConnect({
shards : {
s1 : {host : '127.0.0.1', port : 31017},
s2 : {host : '127.0.0.1', port : 31018},
}
});
Get collection by name
-
name
- collection name
var collection = yield autoconn.collection('player');
Execute func in a transaction, auto commit on success or rollback on error.
The code inside func must be (domain)[https://nodejs.org/api/domain.html] safe.
-
func
- The function to execute, it must return a promise - shardId - Specify shard to execute (required when you have multiple shards)
- Returns: return whatever func returns
Generator style
try{
var player = yield autoconn.transaction(Promise.coroutine(function*(){
// Make queries here
yield autoconn.collection('player').insert({_id : 1, name : 'rain'});
return yield autoconn.collection('player').find(1);
}), 's1');
}
catch(err){
// Handle Error
}
Promise style
return autoconn.transaction(function(){
return Promise.try(function(){
return autoconn.collection('player').insert({_id : 1, name : 'rain'});
})
.then(function(){
return autoconn.collection('player').find(1);
});
}, 's1')
.then(function(ret){
// ret is player
}, function(err){
// Handle error
});
Close autoConnection
yield autoconn.close();
Collection of documents
var coll = conn.collection(name); //Sync API
Find documents based on query.
-
queryOrId
- Query or id. Only field-value pair is supported in query, others operations (like sorting, comparing) are not supported. If you specify a query, make sure the field combination used in the query is declared as index, query not using index is treated as error.
{_id : 1}; //OK!
{name : 'rain', age : 30}; //OK only if 'name' and 'age' is declared as compound index
{age : {$gte : 30}}; //Error! not supported
-
fields
- fields to return
'field1 field2' // return field1 and field2
{key : true} // include key
{key : false} // exclude key
-
opts
- Find options
-
opts.readonly
- true/false (false by default). Specify readonly if you only read document (without modifying or do modification depend on the doc), this is faster. You can callcoll.findReadOnly
to do the same thing. -
opts.limit
- number. Limit number of returned documents.
{
readonly : true,
limit : 10,
}
- Returns:
document
for id,[document]
for query
Example:
var doc = yield coll.find(id);
var doc = yield coll.find(id, 'field');
var doc = yield coll.find(id, {field : false});
var doc = yield coll.find(id, null, {readonly : true});
var docs = yield coll.find({field : value});
Insert documents to collection
-
docs
- doc or [doc]. A doc._id will be generated if you don't specify one. - Returns:
[doc._id]
Example
yield coll.insert({_id : 1, name : 'rain'});
var ids = yield coll.insert([{name : 'rain'}, {name : 'snow'}]);
Update document
-
queryOrId
- Refer to coll.find -
modifier
- Modifiers
- doc - replace with the new doc
-
modifier.$set
- set the specified fields -
modifier.$unset
- remove the specified fields -
modifier.$inc
- inc a field by value, create one if not exists -
modifier.$push
- push a item into array, create new array if not exists -
modifier.$addToSet
- push a item into array if not duplicate -
modifier.$pop
- pop a item from array -
modifier.$pull
- pull a item from array by value
yield coll.update(query, doc);
yield coll.update(query, {$set : {field : value}});
yield coll.update(query, {$unset : {field : true}});
yield coll.update(query, {$inc : {field : 5});
yield coll.update(query, {$push : {field : item}});
yield coll.update(query, {$addToSet : {field : item}});
yield coll.update(query, {$pop : {field : true}});
yield coll.update(query, {$pull : {field : value}});
-
opts
- Options
-
opts.upsert
- Insert if not exists, update if exists
yield coll.update(query, doc, {upsert : true});
- Returns: count of updated
NOTE: DO NOT put large array in a document, which will slow down performance.
Remove documents
-
queryOrId
- Refer to coll.find - Returns: count of removed
yield coll.remove(query);
Equals to (yield coll.find(queryOrId, fields, opts))[0];
Equals to coll.find(id, fields, opts);
Equals to coll.find(queryOrId, fields, {readonly : true});
Equals to (yield coll.find(queryOrId, fields, {readonly : true}))[0];
Equals to coll.find(id, fields, {readonly : true});
Count documents based on query
- query - The format of query equals to coll.find
Example:
var count = yield coll.find({field : value});
The 'mongoose' for memdb.
Mdbgoose is modified from mongoose, so most mongoose API also work in mdbgoose, we just list the difference here. If you want to know how to work with mongoose, please refer to mongoose official doc
var mdbgoose = require('memdb').goose;
Mongoose doesn't support bluebird promise, so we wrap each API suffixed by 'Async' which return a bluebird promise, as below.
yield doc = Model.findAsync(id);
yield doc.saveAsync();
DO NOT use the old callback style
Model.find(id, function(err, ret){
// Bad Practise
});
Specify the target servers, you must call connect before start any transaction. Please refer to memdb.autoConnect
-
opts.shards
- Specify all shards host and port
{
shardId1 : {host : '127.0.0.1', port : 31017},
shardId2 : {host : '127.0.0.1', port : 31018},
}
-
opts.backend
- The backend mongodb config (Optional)
{ url : 'mongodb://localhost/test' }
Example
var shards = {
s1 : {host : '127.0.0.1', port : 31017},
s2 : {host : '127.0.0.1', port : 31018},
};
var backend = {url : 'mongodb://localhost/test'}
yield mdbgoose.connectAsync({shards : shards, backend : backend});
Disconnect from memdb server
yield mdbgoose.disconnectAsync();
Execute func in a transaction, please refer to autoconn.transaction
yield mdbgoose.transactionAsync(P.coroutine(function*(){
var doc = yield Model.findAsync(...);
yield doc.saveAsync();
}), 's1');
Generate memdb collections config from mdbgoose schema. This is useful when you want to define indexes in schema.
Please refer to coll.find
Please refer to coll.findOne
Please refer to coll.findById
Please refer to coll.findReadOnly
Please refer to coll.findOneReadOnly
Please refer to coll.findByIdReadOnly
Please refer to coll.count
- findByIdAndRemove
- findByIdAndUpdate
- findOneAndUpdate
- findOneAndRemove
Index defined in model is for backend mongodb (If you like to make quries from backend mongodb, you can define proper indexes).
For memdb index, you should define in memdb.conf.js, note that live index change is NOT allowed.
The following types are supported
- String
- Number
- Array
- Boolean
- Mixed
The following types are NOT supported
- Date
- Buffer
- ObjectId
MemDB support only field-value pair in query, and the queried fields must be declared as index. If you want more complex query, please refer to access backend mongodb
Model.find({_id : 1}); //OK!
Model.find({name : 'rain', age : 30}); //OK only if 'name' and 'age' is declared as compound index
Model.find({age : {$gte : 30}}); //Error! not supported
You can use mdbgoose to access backend MongoDB (instead of memdb), which is useful when you want complex and non-realtime queries. The data fetched directly from backend MongoDB is readonly, never write directly to backend MongoDB.
The API you can use is below, original mongoose API is renamed with 'Mongo' suffix
- Model.find -> Model.findMongo
- Model.findOne -> Model.findOneMongo
- Model.findById -> Model.findByIdMongo
- Model.count -> Model.countMongo
Node has memory limition of about 1.4GB Each shard has heap limit of 1GB, which can load about 500k documents (larger docs can spend more memory), documents will flush back to backend storage when memory exceed this limit (this will slow down performance), please adjust idleTimeout parameter to balance memory usage and performance.
Collection name can not contain with '$' or begin with 'system.'
Field name can not start with '$' or contains '.'
Each request message can not exceed 1MB after json encoded
Document can not exceed 1MB after json encoded