Sunday, 15 April 2012

mongodb - Aggregation framework flatten subdocument data with parent document -



mongodb - Aggregation framework flatten subdocument data with parent document -

i building dashboard rotates between different webpages. wanting pull slides part of "test" deck , order them appropriately. after query result ideally like.

class="lang-js prettyprint-override">[ { "url" : "http://10.0.1.187", "position": 1, "duartion": 10 }, { "url" : "http://10.0.1.189", "position": 2, "duartion": 3 } ]

i have dataset looks following

class="lang-js prettyprint-override">{ "_id" : objectid("53a612043c24d08167b26f82"), "url" : "http://10.0.1.189", "decks" : [ { "title" : "test", "position" : 2, "duration" : 3 } ] } { "_id" : objectid("53a6103e3c24d08167b26f81"), "decks" : [ { "title" : "test", "position" : 1, "duration" : 2 }, { "title" : "other deck", "position" : 1, "duration" : 10 } ], "url" : "http://10.0.1.187" }

my attempted query looks like:

class="lang-js prettyprint-override">db.slides.aggregate([ { "$match": { "decks.title": "test" } }, { "$sort": { "decks.position": 1 } }, { "$project": { "_id": 0, "position": "$decks.position", "duration": "$decks.duration", "url": 1 } } ]);

but not yield desired results. how can query dataset , expected results in optimal way?

well "flatten" document title suggests $unwind going employed there not other way that. there different approaches if can live array beingness filtered downwards matching element.

basically speaking, if have 1 thing match in array fastest approach utilize .find() matching required element , projecting:

class="lang-js prettyprint-override"> db.slides.find( { "decks.title": "test" }, { "decks.$": 1 } ).sort({ "decks.position": 1 }).pretty()

that still array long have 1 element matches work. items sorted expected, though of course of study "title" field not dropped matched documents, beyond possibilities simple projection.

class="lang-js prettyprint-override">{ "_id" : objectid("53a6103e3c24d08167b26f81"), "decks" : [ { "title" : "test", "position" : 1, "duration" : 2 } ] } { "_id" : objectid("53a612043c24d08167b26f82"), "decks" : [ { "title" : "test", "position" : 2, "duration" : 3 } ] }

another approach, long have mongodb 2.6 or greater available, using $map operator , others in order both "filter" , re-shape array "in-place" without applying $unwind:

class="lang-js prettyprint-override">db.slides.aggregate([ { "$project": { "url": 1, "decks": { "$setdifference": [ { "$map": { "input": "$decks", "as": "el", "in": { "$cond": [ { "$eq": [ "$$el.title", "test" ] }, { "position": "$$el.position", "duration": "$$el.duration" }, false ] } } }, [false] ] } }}, { "$sort": { "decks.position": 1 }} ])

the advantage there can create changes without "unwinding", can cut down processing time big arrays not creating new documents every array fellow member , running separate $match stage "filter" or $project reshape.

class="lang-js prettyprint-override">{ "_id" : objectid("53a6103e3c24d08167b26f81"), "decks" : [ { "position" : 1, "duration" : 2 } ], "url" : "http://10.0.1.187" } { "_id" : objectid("53a612043c24d08167b26f82"), "url" : "http://10.0.1.189", "decks" : [ { "position" : 2, "duration" : 3 } ] }

you can 1 time again either live "filtered" array or if want can 1 time again "flatten" adding in additional $unwind not need filter $match result contains matched items.

but speaking if can live utilize .find() fastest way. otherwise doing fine little data, or there other alternative consideration.

mongodb aggregation-framework

No comments:

Post a Comment