MongoDB single election project

I am having problems changing my document during aggregation for grouping. Basically I want to click records on fields depending on their type. I have a structure as follows:

_id: P1 entities: [{type: A, val: X}, {type: B, val: X}, {type: A, val: Y}] ... 

I want $ unwind and $ to design these objects to get a structure like:

 _id: P1 A: [X] B: [] _id: P1 A: [Y] B: [] _id: P1 A: [] B: [X] 

therefore, I can group by A or B, or both, i.e.

 $group: { _id: { A: $A, B: $B } count: {$sum : 1} 

I thought I could just do:

 $unwind: $entities $project: { id: ยงid A: {"$cond":[{"$eq":["$type","A"]},"$code"]} B: {"$cond":[{"$eq":["$type","B"]},"$code"]} } $group: { _id: "$id" A: {$addToSet : "$A"} } 

or if something like

 $unwind: $entities $group: { _id: "$id" A: {"$cond":[{"$eq":["$type","A"]},$push: "$code", null]} ... } 

but both versions fail because I cannot do anything on the other, and I was not able to use $ push inside the conditional expression. The next I got the project depending on the type, but since I could not find a way to not add anything to the field when there was no match, I get:

 _id: P1 A: [X,null,Y] B: [null,X,null] 

which messed up the count. My second idea was to filter arrays to remove zero. But I did not find a way to delete objects, because again $ cond does not allow me to specify empty / "do nothing" otherwise.

I have a feeling that it can work with grouping by type and content with the correspondence of the required types, but since I have many types and arbitrary groupings, which leads to a grouping tree, it can become very difficult. Ideas or hints of mistakes would be very welcome.

thanks

EDIT: Decision based on anwser

I had to adapt it slightly to filter cases when all type content was null, because otherwise it would be lost during the comparison and because I want to keep this knowledge. Thanks!

 {$project:{ A: {$cond: [ {$eq: ["$A", [false]]}, ["N/A"], "$A" ]}, B: {$cond: [ {$eq: ["$B", [false]]}, ["N/A"], "$B" ]}, }}, { "$unwind": "$A" }, { "$match": { "A": { "$ne": false } } }, { "$group": { "_id": "$_id", "A": { "$push": "$A" }, "B": { "$first": "$B" } }}, { "$unwind": "$B" }, { "$match": { "B": { "$ne": false } } }, { "$group": { "_id": "$_id", "A": { "$first": "$A" }, "B": { "$push": "$B" } }} 
+7
mongodb mongodb-query aggregation-framework
source share
1 answer

You seemed to be on the right track; there are only different approaches to removing these false values โ€‹โ€‹from the conditional. You cannot return anything, but you cn get rid of values โ€‹โ€‹you don't want.

If you really need โ€œsetsโ€ and you have MongoDB 2.6 or higher, you basically filter out false values โ€‹โ€‹using $setDifference :

 db.entities.aggregate([ { "$unwind": "$entities" }, { "$group": { "_id": "$_id", "A": { "$addToSet": { "$cond": [ { "$eq": [ "$entities.type", "A" ] }, "$entities.val", false ] } }, "B": { "$addToSet": { "$cond": [ { "$eq": [ "$entities.type", "B" ] }, "$entities.val", false ] } } }}, { "$project": { "A": { "$setDifference": [ "$A", [false] ] }, "B": { "$setDifference": [ "$B", [false] ] } }} ]) 

Or as one step using the $map operator inside $project :

 db.entities.aggregate([ {"$project": { "A": { "$setDifference": [ { "$map": { "input": "$entities", "as": "el", "in": { "$cond": [ { "$eq": [ "$$el.type", "A" ] }, "$$el.val", false ] } } }, [false] ] }, "B": { "$setDifference": [ { "$map": { "input": "$entities", "as": "el", "in": { "$cond": [ { "$eq": [ "$$el.type", "B" ] }, "$$el.val", false ] } } }, [false] ] } }} ]) 

Or else stay with the common $unwind and $match to filter them out:

 db.entities.aggregate([ { "$unwind": "$entities" }, { "$group": { "_id": "$_id", "A": { "$push": { "$cond": [ { "$eq": [ "$entities.type", "A" ] }, "$entities.val", false ] } }, "B": { "$push": { "$cond": [ { "$eq": [ "$entities.type", "B" ] }, "$entities.val", false ] } } }}, { "$unwind": "$A" }, { "$match": { "A": { "$ne": false } } }, { "$group": { "_id": "$_id", "A": { "$push": "$A" }, "B": { "$first": "$B" } }}, { "$unwind": "$B" }, { "$match": { "B": { "$ne": false } } }, { "$group": { "_id": "$_id", "A": { "$first": "$A" }, "B": { "$push": "$B" } }} ]) 

Using $push for regular arrays or $addToSet for unique sets.

+13
source share

All Articles