Universal model framework, mongodb module
APACHE-2.0 License
Unimodel library for MongoDB.
$ npm install --save unimodel-mongo
In this section, we will walk through basic usage for the library.
Initiate the default connection to mongo:
let mongo = require('unimodel-mongo');
mongo.connect('mongodb://localhost/mongotest');
Create an MongoModel:
let Animal = mongo.createModel(
'Animal', // model/collection name
{ // common-schema specification
animalId: { type: String, index: true, id: true },
name: { type: String, index: true }
}
);
Register the MongoModel with the default model registry:
mongo.model(Animal);
Use the model registry for CRUD operations on the model:
let Animal = mongo.model('Animal');
let animal = Animal.create({ animalId: 'dog-charles-barkley', name: 'Charles Barkley' });
animal.save().then(() => {/* after save! */});
For more information on each of these components, see the generated docs.
MongoDb is a wrapper around a mongodb.Db instance, which ensures a connection is established before allowing operations against the MongoDB server.
A MongoModel is a wrapper around a mongodb.Collection instance, and provides the interface specified
in unimodel.SchemaModel
.
A MongoDocument encapsulates the data that is stored inside MongoDB, and provides the interface specified
in unimodel.SchemaDocument
.
This is an XError wrapper around mongodb.Error objects.
Mongo does directly support indexing map types. To alleviate this, UnimodelMongo implements hidden fields holding map index information, which is stored in a serialized BSON format.
Schema/Index conversion works for both non-compound and compound indexes, as long as the compound index is accessing the same map. For example the following:
let Animal = mongo.createModel('Animal', {
name: { type: String, index: true }
siblingAges: commonSchema.map({}, { age: Number }),
beds: commonSchema.map({}, {
averageSleepTime: { type: Number, index: true },
longestSleepTime: Number,
shortestSleepTime: Number
})
});
Animal.index({ 'beds.averageSleepTime': 1, 'beds.longestSleepTime': 1 });
let dog = Animal.create({
name: 'Charles',
beds: {
Couch: { averageSleepTime: 30 }
}
});
Will save the following raw data into Mongo:
let rawDog = {
name: 'Charles',
beds: {
Couch: { averageSleepTime: 30, longestSleepTiem: 55 }
},
'_mapidx_beds^averageSleepTime': [
BSON.serialize([ 'Couch', 30 ]).toString()
],
'_mapidx_beds^averageSleepTime^longestSleepTime': [
BSON.serialize([ 'Couch', 30, 55 ]).toString()
]
};
But the following compound index would not be allowed, since it is across multiple maps:
Animal.index({ 'siblingAges.age': 1, 'beds.averageSleepTime': 1 });
To create index in background mode, pass an option of backgroundIndex
set to true to connect()
method, like this:
let mongo = require('unimodel-mongo');
mongo.connect({ backgroundIndex: true });
By default, unimodel-mongo creates indexes automatically when setting up database. To disable this behavior, do:
let mongo = require('unimodel-mongo');
mongo.connect({ autoCreateIndex: false });
For a query to properly convert, certain conditions must be met:
For non-compound indexes, the following query operators will be properly converted:
$eq
$lt
$lte
$gt
$gte
let rawQuery = { 'beds.Couch.averageSleepTime': 30 };
Becomes:
let query = { '_mapidx_beds^averageSleepTime': BSON.serialize([ 'Couch', 30 ]).toString() };
For compound indexes, only $eq
is allowed.
So, the following:
let rawQuery = {
'beds.Couch.averageSleepTime': 30
'beds.Couch.longestSleepTime': 55
};
Becomes:
let query = {
'_mapidx_beds^averageSleepTime^longestSleepTime': BSON.serialize([ 'Couch', 30, 55 ]).toString()
};
But the following examples will not be converted without breaking up the components into separate
$and
blocks:
let fail1 = { // Map field must be indexed
'beds.Couch.longestSleepTime': 55
};
let fail2 = { // Multiple maps/keys cannot be in the same block
'beds.Couch.averageSleepTime': 30
'beds.Floor.longestSleepTime': 55
};
let fail3 = { // No invalid query operators
'beds.Couch.averageSleepTime': 30
'beds.Floor.longestSleepTime': { $lt: 55 }
};
let fail4 = { // Extra fields in the map cannot be queried along with the indexed fields
'beds.Couch.averageSleepTime': 30
'beds.Couch.longestSleepTime': 55,
'beds.Couch.shortestSleepTime': 5
};