Here's how I return a list of keys from an associative array (i.e. an embedded document) without also returning their value.
The data structure I have is shown below. It's made up of an associative array [friends], which contains a set of keys (Twitter usernames) and values (details about the user). My aim was to return a list of the Twitter usernames, without all of the details associated to them which - in some cases - could be quite a large amount of data.
[friends] => Array (
[RockSugarBand] => Array (
[realName] => Rock Sugar
...
)
[twitterapi] => Array (
[realName] => Twitter API
...
)
[biz] => Array (
[realName] => Biz Stone
...
)
)
I solved this using MongoDB's 'Group' function. The JavaScript command is:
db.users.group(
{
cond: {_id:ObjectId('4c3c32c24b065884c53f35bb')},
initial: { results: [] },
reduce: function(obj,prev)
{
for(var key in obj.friends) {
prev.results.push(key);
}
}
}
);
What this essentially does is:
...and that's it! The result looks like:
Array (
[results] => Array (
"RockSugarBand",
"twitterapi",
"biz"
)
)
The reason that results is wrapped in an array is that the function will return one results array per Document iterated over. In my case that's just one, but had I used a condition that returned more documents, they would all be included within this wrapping array.
// Use all fields
$keys = array();
// Set initial values
$initial = array("results" => array());
// JavaScript function to perform
$reduce = new MongoCode('function(obj,prev)
{
for(var key in obj.friends) {
prev.results.push(key);
}
}');
// The condition on which a document must match in order to be processed
$condition = array('_id' => $userDocId);
// Execute the query
$result = $collection->group($keys, $initial, $reduce, $condition);
Things to note:
This is just how I solved it. There may well be better solutions. If you know of one, please feel free to share it with us all. :-)