The CommonStorage component

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;

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:

const Ice::CommunicatorPtr ic = getIceManager()->getCommunicator();
// xxx::addFactories(ic)
MongoSerializer serializer(ic, true);

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(); // implements armarx::Serializable
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);
// process fileBuf or store it as a local file

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)) {
// process file chunk in buffer
}
- memoryPrx->releaseFileProxy(filePrx);
}

Remove a file:

dataBasePrx->removeFileById("mydb", fileId);
cyberglove_with_calib_22dof.ic
ic
Definition: cyberglove_with_calib_22dof.py:22
IceInternal::Handle< ::Ice::Communicator >
armarx::flush
const LogSender::manipulator flush
Definition: LogSender.h:251
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174