Code Magician
Code Magician

Reputation: 23972

Searching an array of objects in MongoDB using the C# Driver

Following the advice of this article I created a blob index on an array of objects in my documents. For example:

{
...
    "itemID" : 37,
    "MetaData" : [ 
        {
            "FileExtension" : "TXT"
        }, 
        {
            "EmailSubject" : "GAS DESK HEAD MEETING"
        }, 
        {
            "DocumentType" : "EMAIL"
        }, 
        {
            "Date_BestEmailSent" : ISODate("2001-01-26T04:11:32.000Z")
        }, 
        {
            "Date_ParentDate_BestDate" : ISODate("2001-01-26T04:11:32.000Z")
        }, 
        ...
        ],
    ...
}

I'm now parsing a search tree in C# to build a query using the MongoDB C# driver:

IMongoQuery expression; 
switch (leaf.Op)
{
    case SearchOperation.Equals:
        expression = Query.EQ(leaf.Field, leaf.Value);
        break;
    case SearchOperation.Contains:
        expression = Query.Matches(leaf.Field, leaf.Field);
        break;
    ...
}

if (_rootLevelFields.Contains(leaf.Field))
{
    return expression;
}
return Query.ElemMatch("MetaData", expression);

In this case, if my search criteria was FileExtension EQ 'TXT' It would run:

db.test.find({"MetaData": {$elemMatch: {"FileExtension":"TXT"}}})

This runs very slowly and the explain indicates it's scanning all records and not using my Index. If I manually run:

db.test.find({"MetaData": {"FileExtension":"TXT"}})

It uses the index and runs much faster. In this case it appears I don't want to use ElemMatch but the MongoDB Builder namespace doesn't seem to accommodate this type of query e.g.

Query.EQ("MetaData", expression);

is not syntactically correct. I've poured over the documentation and even the MongoDB driver source code but can't find how to do what I want. Am I missing something obvious?

Upvotes: 2

Views: 1433

Answers (1)

Christian P
Christian P

Reputation: 12240

The EQ method accepts only BSONValue as a parameter, but you're trying to pass a IMongoQuery instance.

In your second query you're basically searching this document in MetaData array :

{"FileExtension":"TXT"}

You will need to create a new BsonDocument and pass it into your EQ method:

Query.EQ("MetaData", new BsonDocument(leaf.Field, leaf.Value));

You can check the documentation for EQ method for more details.

Upvotes: 1

Related Questions