2014년 12월 13일 토요일

Conditional projection with arrays.

I am basically doing an aggregation to count the number of documents that falls on specific criteria. I am not using Map reduce because I want to do more than one at once.

this is an example of my document

{
   
"_id" : ...,
   
"Field1" : ....,
   
"Field2" : ....,
   
"Field3" : ....,
   
"FieldDocument1" : {
        "Field5" : ....,
        
"Field6" : ....,
        
......
   },
   
"FieldDocument2" : {
        
"Field7" : ....,
        
"FieldArray1" : [....],
        
"FieldArray2" : [
               
"Field8" : value,
               
"FieldArrayToQuery" : [
                                       
{"FieldToQuery1" : value,"FieldToQuery1" : value},
           
                                                        {"FieldToQuery1" : value,"FieldToQuery1" : value},
                                ]
,
        ],        ......
   
}
}

And this is my query:

db.events.aggregate([
    {$match : {
        "Field1": value
    }},
    {$project: {
        count : { $literal: "count" },
        count1: {
                $cond:[{$eq : [ "$FieldDocument1.Field5" , value]},1,0]
        },
        count2: {
                $cond:[
                        {"FieldDocument2.FieldArray2.FieldArrayToQuery" : { $elemMatch : { FieldToQuery1: value, FieldToQuery1: value}}},
                        1,
                        0
                      ]
        }
        
    }},
    {$group : {
            _id : "$count",
            count1Count : {$sum: "$count1"},
            count2Count : {$sum: "$count2"},
    }},
])

The first count works fine, but when I add the second count I get this error message:

uncaught exception: aggregate failed: {
"errmsg" : "exception: dotted field names are only allowed at the top level",
"code" : 16405,
"ok" : 0
}

is there anyway to have complex conditional projection with arrays?



Not quite like that - can you explain what you want to have as a
result (rather than aggregate syntax you are trying to use).
I'm not sure if I'm understanding what you want to get - and I
hesitate to make a suggestion since it might be for slightly
difference scenario than you have.



Basically, What I am trying to do is multiple counts based on different criteria at once.

I want to do a count based on different fields and an criteria, but all of them have a common criteria, so I was hoping to get them all at once. I managed to get most of them, but I am running on trouble when try to do conditional projection for arrays.

Any advise?



The problem is the syntax you are using is for find or $match, not $project:

 {"FieldDocument2.FieldArray2.FieldArrayToQuery" : { $elemMatch : {
FieldToQuery1: value, FieldToQuery1: value}}} is not a legal way to
compare fields in a conditional ($cond) projection.

You can use {$and:[ {$eq:[ "field1",value1  ] }, { $eq : [ $field2",value2 ] } ]

But you have to unwind arrays before you pass them through group for
aggregation...



Thanks Kamsky!

I was hoping to do it without unwinding, :(. 

I'm doing it now with map reduce, because I cannot accomplish what I want just with Aggregation.


댓글 없음:

댓글 쓰기