0

Working with C# and mongo I'm checking some of the different ways to query. Currently I have a collection of trips and each trip has an array of expenses. Each expence has it's own objectId.

First I had this query to locate a specific query to update. The trick was the secondpart where I dot my way into the id of the expense.

var Update = Query.And(
   Query<Trip>.EQ(t => t.Id, ObjectId.Parse(tripId)), 
   Query<Expense>.EQ( "Expenses._id", ObjectId.Parse(id)));

As I did a typo in here and named it Expenses._Id with a capital I I was looking for a way to move away from the "loose strings".

I tried this

var tripToUpdate = Query.And(
    Query<Trip>.EQ(t => t.Id, ObjectId.Parse(tripId)), 
    Query<Expense>.EQ(e => e.Id, ObjectId.Parse(id)));

But it got translated into

{ "$and" : [{ "_id" : ObjectId("5224f0208c74943810d333f6") }, 
            { "_id" : ObjectId("5224f0488c74943810d333f7") }] }

And not the expected Expense._id. I guess I would need some kind of convention for this to be supported.

Is it at all possible to write it in a more strongly typed manner men not only querying?

For querying I'm already using the std C# provider.

Rasmus Christensen
  • 8,321
  • 12
  • 51
  • 78
  • Please post the structure of your documents as JSON. The driver behaves correctly here, it's not clear to me what you want the query to be. What query do you expect? – mnemosyn Sep 02 '13 at 21:18
  • I expect the first query as the second does not make sense. Meaning that I specify two _id and not Expenses._id for the second – Rasmus Christensen Sep 02 '13 at 21:49
  • @RasmusChristensen If you have found an answer to your question you should post it as an *answer*, rather than as an edit to the question. – Servy Sep 09 '13 at 19:23
  • @Servy The answer was given below, I just improved the usage in my use case. – Rasmus Christensen Sep 09 '13 at 20:52
  • @RasmusChristensen If you have built upon an existing answer and used that to create some other solution that you wish to post then you should post *that* in an answer, rather than as an edit to the question. – Servy Sep 09 '13 at 20:55

2 Answers2

0

Yes, something similar is possible, it doesn't create the same query, but for the query given, it doesn't make a difference:

var query =
    from c in collection.AsQueryable<Trip>()
    where c.Id == trip.Id
    where c.Expenses.Any(p => p.Id == myId)
    select c;

or

var query = 
    collection.FindAs<Trip>(
        Query.And(
            Query<Trip>.EQ(p => p.Id, trip.Id),
            Query<Trip>.ElemMatch(p => p.Expenses, q => q.EQ(x => x.Id, myId))));

However, note that both will create an $elemMatch query like this:

{
  "_id" : ObjectId("522512c5298f241198548b9d"),
  "Expenses" : {
        "$elemMatch" : {
                "_id" : ObjectId("522512c5298f241198548b9b")
        }
}

elemMatch will check if one single element in the array matches all the conditions. In this case, where there is only one condition for the array elements, that's the same thing, but it's not the same query.

i3arnon
  • 113,022
  • 33
  • 324
  • 344
mnemosyn
  • 45,391
  • 6
  • 76
  • 82
0

Based on the answer from @mnemosyn I came up with this solution improved by adding a downcast.

After the great input I ended up using first the ElemenMatch, but after some further search on stackoverflow I spotted the downcast from IQueryable to an MongoQueryable as mentioned here

Translate Queryable<T> back to IMongoQuery

After this the code would be like:

var query =
        .Trips.AsQueryable()
        .Where(c => c.Id == ObjectId.Parse(tripId) && c.Expenses.Any(p => p.Id == ObjectId.Parse(id)));

Followed by a downcast to an MongoQuery

var mongoQuery = ((MongoQueryable<Trip>) query).GetMongoQuery();

Works really great.

Community
  • 1
  • 1
Rasmus Christensen
  • 8,321
  • 12
  • 51
  • 78