Introduction
CommonStorage can be seen as an ArmarX interface for MongoDB. It allows to store arbitrary JSON objects in Mongo collections as well as files in GridFS.
Configuration
Following properties are supported:
- MongoHost: host where MongoDB daemon is running. Format: hostname[:port]
- MongoAuth: whether authentication should be used when connecting to MongoDB (true/false)
- MongoUser: username to authenticate with (only if MongoAuth=true)
- MongoPassword: password to authenticate with (only if MongoAuth=true)
Quick tutorial
As usual, you need to acquire a proxy first:
dataBasePrx = getProxy<CommonStorageInterfacePrx>("CommonStorage");
Working with collections and documents
Then, open a collection. Please note, that fully qualified MongoDB namespace(=dbname.collectionname) must be specified:
CollectionPrx actionCollectionPrx = dataBasePrx->requestCollection("memdb.actions");
Now you can store a document(=MongoDB record):
DBStorableData action;
action1.JSON = "{name: 'take', params: ['what'], prereq: []}";
const std::string actionID = actionCollectionPrx->insert(action);
insert() function will return an auto-generated unique document id in the MongoDB collection. If you have a natural key and would like to use it instead of a generated value, just set "_id" field in JSON.
Updating a document:
action.JSON = "{name: 'take', params: ['what'], prereq: [], effects: [{pred: 'isIn', params: ['what', 'hand'] }] }";
actionCollectionPrx->updateWithUserKey(action, "name");
This version will search for a document with name="take" and update it using JSON provided. Use update() function to match by document id ("_id" field).
There is also a so-called "upsert" (update-or-insert) function available:
const std::string actionID = actionCollectionPrx->save(action);
It will update the document with the same id, if present, and insert a new one otherwise.
Querying:
const std::string findQuery = "{name: 'take'}";
DBStorableDataList actions = actionCollectionPrx->findByQuery(findQuery);
for (DBStorableDataList::const_iterator it = actions.begin(); it != actions.end(); ++it)
ARMARX_INFO <<
"Found action by name: " << it->JSON << flush;
#define ARMARX_INFO
The normal logging level.
Removing a document by id:
actionCollectionPrx->removeByMongoId(actionID);
Finally, close a collection when you're done:
dataBasePrx->releaseCollection(actionCollectionPrx);
You can also find an example code in CommonStorageExample application.
Using MongoSerializer
Since constructing and parsing JSON "by hand" is mostly impractical, there is another option available:
- implement armarx::Serializable interface in your data class (see Serialization)
- use MongoSerializer to convert class instances to/from JSON
Here is a short three-step HOWTO.
Init serializer:
MongoSerializer serializer(ic, true);
::IceInternal::Handle<::Ice::Communicator > CommunicatorPtr
Save a document:
armarx::SerializablePtr action = ...
DBStorableData dbAction = serializer->serialize(action);
actionCollectionPrx->insert(dbAction);
Load a document:
const DBStorableData dbAction = actionCollectionPrx->findByMongoId(actionID);
armarx::SerializablePtr action = new MyAction();
serializer->deserialize(dbAction, action);
Working with files in GridFS
GridFS is standard for storing files in a database, supported by MongoDB. Files are stored on per-database basis, i.e. each Mongo database has its own "filesystem". Inside the filesystem a specific file can be identified by its name or id, but unlike id, name is NOT guaranteed to be unique. Thus to identify a file globally in the scope of MongoDB instance, a pair of (database_name, file_id) is used.
CommonStorage provides basic, "low-level" functions to manage files in GridFS. For advanced functionality including caching and file reference attributes please refer to GridFS files and file reference attributes section.
Some of the most important functions are introduced below.
Store a file:
const std::string fileId = dataBasePrx->storeFile("mydb", "/home/alex/localfile", "gridFSFileName");
Get a complete text file into sting buffer:
const std::string fileBuf;
dataBasePrx->getTextFileById("mydb", fileId, fileBuf);
File size must be smaller than maximal ICE message size (typically 1MB). For large files use the second option described below.
Get a file chunk-by-chunk:
GridFileInterfacePrx filePrx = memoryPrx->getFileProxyById("mydb", fileId);
if (filePrx) {
memoryx::Blob buffer;
while (filePrx->getNextChunk(buffer)) {
}
- memoryPrx->releaseFileProxy(filePrx);
}
Remove a file:
dataBasePrx->removeFileById("mydb", fileId);