Hi all,
I am looking into using mongo for our web application that I have taken over the maintenance for and have several questions so please excuse all the spam :)
My first question is how I can integrate mongo into our framework model. This _should_ be easy as when the app was designed the storage layer was abstracted away from the developer using a storage interface which implement the following methods (there are more but I have left them out for simplicity)
/// <summary>
/// Returns a ArrayList of objects that comply to the provided template. Query by example using <paramref name="template"/> as the example.
/// </summary>
/// <param name="template">Search example</param>
/// <returns>Arraylist of objects that are similar to the example provided.</returns>
public override ArrayList Get(object template)
{
return this.Get(template, null, null);
}
public override ArrayList Get(object template, ConstraintList constraints)
{
return this.Get(template, constraints, null);
}
public override ArrayList Get(object template, ConstraintList constraints, SortExpression sort)
{
//do some mongo stuff
}
public override int GetCount(object template)
{
return 1;
}
public override int GetCount(object template, Search.ConstraintList constraints)
{
}
public override Dictionary<object, int> GetDistinctCount(object template, string propertyName)
{
}
public override Dictionary<object, int> GetDistinctCount(object template, string propertyName, Search.ConstraintList constraints)
{
}
public override void Delete(object obj)
{
return;
}
public override void Set(object obj)
{
//what type are we getting?
string typename = obj.GetType().ToString();
string connectionString = "mongodb://localhost";
MongoServer server = MongoServer.Create(connectionString);
MongoDatabase dataSource = server.GetDatabase(this.dataSourceDescription);
using (server.RequestStart(dataSource))
{
MongoCollection<BsonDocument> coll =
dataSource.GetCollection<BsonDocument>(typename);
// BsonDocument book = new BsonDocument {
// { "author", "Ernest Hemingway" },
// { "title", "For Whom the Bell Tolls" }
//};
coll.Insert(obj);
}
}
//this is essentially the update command
public override object SetRemoteObject(object obj)
{
}
public override object GetObjectByID(string storageID, Type type)
{
string typename = type.ToString();
string connectionString = "mongodb://localhost";
MongoServer server = MongoServer.Create(connectionString);
MongoDatabase dataSource = server.GetDatabase(this.dataSourceDescription);
using (server.RequestStart(dataSource))
{
// a series of operations that must be performed on the same connection
MongoCollection<BsonDocument> coll = dataSource.GetCollection(typename);
var query = new QueryDocument();
query.Add("id", BsonValue.Create(storageID));
//loop through the template object and foreach non-null property add it to the query, TODO must be a better way
BsonDocument document = coll.FindOne(query);
return document;
}
}
As you can see, every call to a storage function in the application passes a template object (which differ in type of course depending what part of the app/what plugin is calling the funciton etc)
my problem is using this template object to build a query
here is an example of a call to get using a template object:
User template = (User)FormatterServices.GetUninitializedObject(typeof(User));
template.GlobalLogonName = User.getGlobalLogonName(Configuration.ServerName, logonName);
ArrayList resultList = container.Get(template);
Now, because the class User contains datetimes which cannot be null, when I build a querydocument by iterating through all the templates properties using reflection the querydocument will never return a value from the db because it's searching for users that have datefields initialised to 1/1/1970
Here is my junk code that I am currently using to query the db.
The below code works well because all I am interested in is the document ID:
public override object GetObjectByID(string storageID, Type type)
{
string typename = type.ToString();
string connectionString = "mongodb://localhost";
MongoServer server = MongoServer.Create(connectionString);
MongoDatabase dataSource = server.GetDatabase(this.dataSourceDescription);
using (server.RequestStart(dataSource))
{
// a series of operations that must be performed on the same connection
MongoCollection<BsonDocument> coll = dataSource.GetCollection(typename);
var query = new QueryDocument();
query.Add("id", BsonValue.Create(storageID));
BsonDocument document = coll.FindOne(query);
return document;
}
}
public override ArrayList Get(object template, ConstraintList constraints, SortExpression sort)
{
//what type are we getting?
Type t = template.GetType();
string typename = t.ToString();
//todo config
string connectionString = "mongodb://localhost";
MongoServer server = MongoServer.Create(connectionString);
MongoDatabase dataSource = server.GetDatabase(this.dataSourceDescription);
ArrayList result = new ArrayList();
using (server.RequestStart(dataSource))
{
// a series of operations that must be performed on the same connection
MongoCollection<BsonDocument> coll = dataSource.GetCollection(typename);
QueryDocument query = buildQueryDocumentFromObjectTemplate(template);
//if query length is 0, then we want all documents of this type in the db
if (query.Count() == 0)
{
MongoCursor<BsonDocument> results = coll.FindAll();
foreach (BsonDocument document in results)
{
//result.Add(document);
// object someObject = document.Deserialize(BsonReader.Create(document), template.GetType(), null);
try
{
object someObject = BsonSerializer.Deserialize(document, t);
result.Add(someObject);
string breaker = "dfdf";
}
catch (Exception e)
{
//me
string test = "sd";
}
}
}
else
{
foreach (BsonDocument document in coll.Find(query))
{
// object someObject = document.Deserialize(BsonReader.Create(document), template.GetType(), null);
try
{
object someObject = BsonSerializer.Deserialize(document, t);
result.Add(someObject);
}
catch (Exception e)
{
string grrrrr = "sdsdsd";
}
}
}
//somehow convert my results to the original type so calling method can work with them
//
}
//;
//try
//{
// server.RequestDone();
//}
//catch
//{
// Debug.WriteLine("couldnt close request");
//}
Debug.WriteLine("done" + typename);
return result;
//dataSource.GetCollection(template.GetType().ToString());
}
private static QueryDocument buildQueryDocumentFromObjectTemplate(object template)
{
var query = new QueryDocument();
Type t = template.GetType();
//loop through the template object and foreach non-null property add it to the query, TODO must be a better way
foreach (PropertyInfo p in t.GetProperties())
{
if (p.GetCustomAttributes(typeof(Storage.Attributes.StorageIgnoreAttribute), false).Count() > 0)
continue;
// Write the name and the value
if (p.GetValue(template, null) != null)
{
try
{
query.Add(new BsonElement(p.Name, BsonValue.Create(p.GetValue(template, null))));
}
catch
{
}
}
}
return query;
}
So, in short, whats the best way to query mongodb using a search template object that can have any type and return the search results as an arraylist of objects.
Thanks for any pointers,
Craig